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 " << role.ToString() << " 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 " << role.ToString() << "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 << "Root metadata not present";
604  return false;
605  } else if (result != SQLITE_ROW) {
606  LOG_ERROR << "Can't get Root metadata: " << 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 << "Root metadata not present";
621  return false;
622  } else if (result != SQLITE_ROW) {
623  LOG_ERROR << "Can't get Root metadata: " << 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 Root metadata: " << 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 << role.ToString() << " metadata not present";
651  return false;
652  } else if (result != SQLITE_ROW) {
653  LOG_ERROR << "Can't get " << role.ToString() << " metadata: " << 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  // The Secondary only knows about itself and in its database it is considered
1217  // a Primary, for better or worse.
1218  if (ecu_serial.empty()) {
1219  auto statement = db.prepareStatement("SELECT serial FROM ecus WHERE is_primary = 1;");
1220  if (statement.step() == SQLITE_ROW) {
1221  ecu_serial = statement.get_result_col_str(0).value();
1222  } else if (statement.step() == SQLITE_DONE) {
1223  LOG_DEBUG << "No serial found in database for this ECU, defaulting to empty serial";
1224  } else {
1225  LOG_ERROR << "Error getting serial for this ECU, defaulting to empty serial: " << db.errmsg();
1226  }
1227  }
1228 
1229  if (!ecu_serial.empty()) {
1230  auto statement = db.prepareStatement<std::string>("SELECT hardware_id FROM ecus WHERE serial = ?;", ecu_serial);
1231  if (statement.step() == SQLITE_ROW) {
1232  ecu_map.insert(
1233  {Uptane::EcuSerial(ecu_serial), Uptane::HardwareIdentifier(statement.get_result_col_str(0).value())});
1234  } else if (statement.step() == SQLITE_DONE) {
1235  LOG_DEBUG << "No hardware ID found in database for ECU serial " << ecu_serial;
1236  } else {
1237  LOG_ERROR << "Error getting hardware ID for ECU serial " << ecu_serial << ": " << db.errmsg();
1238  }
1239  }
1240 }
1241 
1242 bool SQLStorage::loadInstallationLog(const std::string& ecu_serial, std::vector<Uptane::Target>* log,
1243  bool only_installed) {
1244  SQLite3Guard db = dbConnection();
1245 
1246  std::string ecu_serial_real = ecu_serial;
1247  Uptane::EcuMap ecu_map;
1248  loadEcuMap(db, ecu_serial_real, ecu_map);
1249 
1250  std::string query =
1251  "SELECT id, sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1252  "ecu_serial = ? ORDER BY id;";
1253  if (only_installed) {
1254  query =
1255  "SELECT id, sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1256  "ecu_serial = ? AND was_installed = 1 ORDER BY id;";
1257  }
1258 
1259  auto statement = db.prepareStatement<std::string>(query, ecu_serial_real);
1260  int statement_state;
1261 
1262  std::vector<Uptane::Target> new_log;
1263  std::map<int64_t, size_t> ids_map;
1264  size_t k = 0;
1265  while ((statement_state = statement.step()) == SQLITE_ROW) {
1266  try {
1267  auto id = statement.get_result_col_int(0);
1268  auto sha256 = statement.get_result_col_str(1).value();
1269  auto filename = statement.get_result_col_str(2).value();
1270  auto hashes_str = statement.get_result_col_str(3).value();
1271  auto length = statement.get_result_col_int(4);
1272  auto correlation_id = statement.get_result_col_str(5).value();
1273  auto custom_str = statement.get_result_col_str(6).value();
1274 
1275  // note: sha256 should always be present and is used to uniquely identify
1276  // a version. It should normally be part of the hash list as well.
1277  std::vector<Uptane::Hash> hashes = Uptane::Hash::decodeVector(hashes_str);
1278 
1279  auto find_sha256 = std::find_if(hashes.cbegin(), hashes.cend(),
1280  [](const Uptane::Hash& h) { return h.type() == Uptane::Hash::Type::kSha256; });
1281  if (find_sha256 == hashes.cend()) {
1282  LOG_WARNING << "No sha256 in hashes list";
1283  hashes.emplace_back(Uptane::Hash::Type::kSha256, sha256);
1284  }
1285 
1286  Uptane::Target t(filename, ecu_map, hashes, static_cast<uint64_t>(length), correlation_id);
1287  if (!custom_str.empty()) {
1288  std::istringstream css(custom_str);
1289  std::string errs;
1290  Json::Value custom;
1291  if (Json::parseFromStream(Json::CharReaderBuilder(), css, &custom, nullptr)) {
1292  t.updateCustom(custom);
1293  } else {
1294  LOG_ERROR << "Unable to parse custom data: " << errs;
1295  }
1296  }
1297  new_log.emplace_back(t);
1298 
1299  ids_map[id] = k;
1300  k++;
1301  } catch (const boost::bad_optional_access&) {
1302  LOG_ERROR << "Incompleted installed version, keeping old one";
1303  return false;
1304  }
1305  }
1306 
1307  if (statement_state != SQLITE_DONE) {
1308  LOG_ERROR << "Can't get installed_versions: " << db.errmsg();
1309  return false;
1310  }
1311 
1312  if (log == nullptr) {
1313  return true;
1314  }
1315 
1316  *log = std::move(new_log);
1317 
1318  return true;
1319 }
1320 
1321 bool SQLStorage::loadInstalledVersions(const std::string& ecu_serial, boost::optional<Uptane::Target>* current_version,
1322  boost::optional<Uptane::Target>* pending_version) {
1323  SQLite3Guard db = dbConnection();
1324 
1325  std::string ecu_serial_real = ecu_serial;
1326  Uptane::EcuMap ecu_map;
1327  loadEcuMap(db, ecu_serial_real, ecu_map);
1328 
1329  auto read_target = [&ecu_map](SQLiteStatement& statement) -> Uptane::Target {
1330  auto sha256 = statement.get_result_col_str(0).value();
1331  auto filename = statement.get_result_col_str(1).value();
1332  auto hashes_str = statement.get_result_col_str(2).value();
1333  auto length = statement.get_result_col_int(3);
1334  auto correlation_id = statement.get_result_col_str(4).value();
1335  auto custom_str = statement.get_result_col_str(5).value();
1336 
1337  // note: sha256 should always be present and is used to uniquely identify
1338  // a version. It should normally be part of the hash list as well.
1339  std::vector<Uptane::Hash> hashes = Uptane::Hash::decodeVector(hashes_str);
1340 
1341  auto find_sha256 = std::find_if(hashes.cbegin(), hashes.cend(),
1342  [](const Uptane::Hash& h) { return h.type() == Uptane::Hash::Type::kSha256; });
1343  if (find_sha256 == hashes.cend()) {
1344  LOG_WARNING << "No sha256 in hashes list";
1345  hashes.emplace_back(Uptane::Hash::Type::kSha256, sha256);
1346  }
1347  Uptane::Target t(filename, ecu_map, hashes, static_cast<uint64_t>(length), correlation_id);
1348  if (!custom_str.empty()) {
1349  std::istringstream css(custom_str);
1350  Json::Value custom;
1351  std::string errs;
1352  if (Json::parseFromStream(Json::CharReaderBuilder(), css, &custom, &errs)) {
1353  t.updateCustom(custom);
1354  } else {
1355  LOG_ERROR << "Unable to parse custom data: " << errs;
1356  }
1357  }
1358 
1359  return t;
1360  };
1361 
1362  if (current_version != nullptr) {
1363  auto statement = db.prepareStatement<std::string>(
1364  "SELECT sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1365  "ecu_serial = ? AND is_current = 1 LIMIT 1;",
1366  ecu_serial_real);
1367 
1368  if (statement.step() == SQLITE_ROW) {
1369  try {
1370  *current_version = read_target(statement);
1371  } catch (const boost::bad_optional_access&) {
1372  LOG_ERROR << "Could not read current installed version";
1373  return false;
1374  }
1375  } else {
1376  LOG_TRACE << "Cannot get current installed version: " << db.errmsg();
1377  *current_version = boost::none;
1378  }
1379  }
1380 
1381  if (pending_version != nullptr) {
1382  auto statement = db.prepareStatement<std::string>(
1383  "SELECT sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1384  "ecu_serial = ? AND is_pending = 1 LIMIT 1;",
1385  ecu_serial_real);
1386 
1387  if (statement.step() == SQLITE_ROW) {
1388  try {
1389  *pending_version = read_target(statement);
1390  } catch (const boost::bad_optional_access&) {
1391  LOG_ERROR << "Could not read pending installed version";
1392  return false;
1393  }
1394  } else {
1395  LOG_TRACE << "Cannot get pending installed version: " << db.errmsg();
1396  *pending_version = boost::none;
1397  }
1398  }
1399 
1400  return true;
1401 }
1402 
1403 bool SQLStorage::hasPendingInstall() {
1404  SQLite3Guard db = dbConnection();
1405 
1406  auto statement = db.prepareStatement("SELECT count(*) FROM installed_versions where is_pending = 1");
1407  if (statement.step() != SQLITE_ROW) {
1408  LOG_ERROR << "Can't get tables count: " << db.errmsg();
1409  throw std::runtime_error("Could not count pending installations");
1410  }
1411 
1412  return statement.get_result_col_int(0) > 0;
1413 }
1414 
1415 void SQLStorage::getPendingEcus(std::vector<std::pair<Uptane::EcuSerial, Uptane::Hash>>* pendingEcus) {
1416  SQLite3Guard db = dbConnection();
1417 
1418  auto statement = db.prepareStatement("SELECT ecu_serial, sha256 FROM installed_versions where is_pending = 1");
1419  int statement_result = statement.step();
1420  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1421  throw std::runtime_error("Failed to get ECUs with a pending target installation: " + db.errmsg());
1422  }
1423 
1424  std::vector<std::pair<Uptane::EcuSerial, Uptane::Hash>> ecu_res;
1425 
1426  if (statement_result == SQLITE_DONE) {
1427  // if there are no any record in the DB
1428  return;
1429  }
1430 
1431  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1432  std::string ecu_serial = statement.get_result_col_str(0).value();
1433  std::string hash = statement.get_result_col_str(1).value();
1434  ecu_res.emplace_back(
1435  std::make_pair(Uptane::EcuSerial(ecu_serial), Uptane::Hash(Uptane::Hash::Type::kSha256, hash)));
1436  }
1437 
1438  if (pendingEcus != nullptr) {
1439  *pendingEcus = std::move(ecu_res);
1440  }
1441 }
1442 
1443 void SQLStorage::clearInstalledVersions() {
1444  SQLite3Guard db = dbConnection();
1445 
1446  if (db.exec("DELETE FROM installed_versions;", nullptr, nullptr) != SQLITE_OK) {
1447  LOG_ERROR << "Can't clear installed_versions: " << db.errmsg();
1448  return;
1449  }
1450 }
1451 
1452 void SQLStorage::saveEcuInstallationResult(const Uptane::EcuSerial& ecu_serial,
1454  SQLite3Guard db = dbConnection();
1455 
1456  auto statement = db.prepareStatement<std::string, int, std::string, std::string>(
1457  "INSERT OR REPLACE INTO ecu_installation_results (ecu_serial, success, result_code, description) VALUES "
1458  "(?,?,?,?);",
1459  ecu_serial.ToString(), static_cast<int>(result.success), result.result_code.toRepr(), result.description);
1460  if (statement.step() != SQLITE_DONE) {
1461  LOG_ERROR << "Can't set ecu installation result: " << db.errmsg();
1462  return;
1463  }
1464 }
1465 
1466 bool SQLStorage::loadEcuInstallationResults(
1467  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>>* results) {
1468  SQLite3Guard db = dbConnection();
1469 
1470  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>> ecu_res;
1471 
1472  // keep the same order as in ecus (start with primary)
1473  auto statement = db.prepareStatement(
1474  "SELECT ecu_serial, success, result_code, description FROM ecu_installation_results INNER JOIN ecus ON "
1475  "ecus.serial = ecu_serial ORDER BY ecus.id;");
1476  int statement_result = statement.step();
1477  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1478  LOG_ERROR << "Can't get ecu_installation_results: " << db.errmsg();
1479  return false;
1480  }
1481 
1482  if (statement_result == SQLITE_DONE) {
1483  // if there are no any record in the DB
1484  return false;
1485  }
1486 
1487  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1488  try {
1489  std::string ecu_serial = statement.get_result_col_str(0).value();
1490  auto success = static_cast<bool>(statement.get_result_col_int(1));
1491  data::ResultCode result_code = data::ResultCode::fromRepr(statement.get_result_col_str(2).value());
1492  std::string description = statement.get_result_col_str(3).value();
1493 
1494  ecu_res.emplace_back(Uptane::EcuSerial(ecu_serial), data::InstallationResult(success, result_code, description));
1495  } catch (const boost::bad_optional_access&) {
1496  return false;
1497  }
1498  }
1499 
1500  if (results != nullptr) {
1501  *results = std::move(ecu_res);
1502  }
1503 
1504  return true;
1505 }
1506 
1507 void SQLStorage::storeDeviceInstallationResult(const data::InstallationResult& result, const std::string& raw_report,
1508  const std::string& correlation_id) {
1509  SQLite3Guard db = dbConnection();
1510 
1511  auto statement = db.prepareStatement<int, std::string, std::string, std::string, std::string>(
1512  "INSERT OR REPLACE INTO device_installation_result (unique_mark, success, result_code, description, raw_report, "
1513  "correlation_id) "
1514  "VALUES (0,?,?,?,?,?);",
1515  static_cast<int>(result.success), result.result_code.toRepr(), result.description, raw_report, correlation_id);
1516  if (statement.step() != SQLITE_DONE) {
1517  LOG_ERROR << "Can't set device installation result: " << db.errmsg();
1518  return;
1519  }
1520 }
1521 
1522 bool SQLStorage::loadDeviceInstallationResult(data::InstallationResult* result, std::string* raw_report,
1523  std::string* correlation_id) {
1524  SQLite3Guard db = dbConnection();
1525 
1526  data::InstallationResult dev_res;
1527  std::string raw_report_res;
1528  std::string corrid_res;
1529 
1530  auto statement = db.prepareStatement(
1531  "SELECT success, result_code, description, raw_report, correlation_id FROM device_installation_result;");
1532  int statement_result = statement.step();
1533  if (statement_result == SQLITE_DONE) {
1534  LOG_TRACE << "No device installation result in db";
1535  return false;
1536  } else if (statement_result != SQLITE_ROW) {
1537  LOG_ERROR << "Can't get device_installation_result: " << db.errmsg();
1538  return false;
1539  }
1540 
1541  try {
1542  auto success = static_cast<bool>(statement.get_result_col_int(0));
1543  data::ResultCode result_code = data::ResultCode::fromRepr(statement.get_result_col_str(1).value());
1544  std::string description = statement.get_result_col_str(2).value();
1545  raw_report_res = statement.get_result_col_str(3).value();
1546  corrid_res = statement.get_result_col_str(4).value();
1547 
1548  dev_res = data::InstallationResult(success, result_code, description);
1549  } catch (const boost::bad_optional_access&) {
1550  return false;
1551  }
1552 
1553  if (result != nullptr) {
1554  *result = std::move(dev_res);
1555  }
1556 
1557  if (raw_report != nullptr) {
1558  *raw_report = std::move(raw_report_res);
1559  }
1560 
1561  if (correlation_id != nullptr) {
1562  *correlation_id = std::move(corrid_res);
1563  }
1564 
1565  return true;
1566 }
1567 
1568 void SQLStorage::saveEcuReportCounter(const Uptane::EcuSerial& ecu_serial, const int64_t counter) {
1569  SQLite3Guard db = dbConnection();
1570 
1571  auto statement = db.prepareStatement<std::string, int64_t>(
1572  "INSERT OR REPLACE INTO ecu_report_counter (ecu_serial, counter) VALUES "
1573  "(?,?);",
1574  ecu_serial.ToString(), counter);
1575  if (statement.step() != SQLITE_DONE) {
1576  LOG_ERROR << "Can't set ecu counter: " << db.errmsg();
1577  return;
1578  }
1579 }
1580 
1581 bool SQLStorage::loadEcuReportCounter(std::vector<std::pair<Uptane::EcuSerial, int64_t>>* results) {
1582  SQLite3Guard db = dbConnection();
1583 
1584  std::vector<std::pair<Uptane::EcuSerial, int64_t>> ecu_cnt;
1585 
1586  // keep the same order as in ecus (start with primary)
1587  auto statement = db.prepareStatement(
1588  "SELECT ecu_serial, counter FROM ecu_report_counter INNER JOIN ecus ON "
1589  "ecus.serial = ecu_serial ORDER BY ecus.id;");
1590  int statement_result = statement.step();
1591  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1592  LOG_ERROR << "Can't get ecu_report_counter: " << db.errmsg();
1593  return false;
1594  }
1595 
1596  if (statement_result == SQLITE_DONE) {
1597  // if there are no any record in the DB
1598  return false;
1599  }
1600 
1601  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1602  try {
1603  std::string ecu_serial = statement.get_result_col_str(0).value();
1604  int64_t counter = statement.get_result_col_int(1);
1605 
1606  ecu_cnt.emplace_back(Uptane::EcuSerial(ecu_serial), counter);
1607  } catch (const boost::bad_optional_access&) {
1608  return false;
1609  }
1610  }
1611 
1612  if (results != nullptr) {
1613  *results = std::move(ecu_cnt);
1614  }
1615 
1616  return true;
1617 }
1618 
1619 void SQLStorage::saveReportEvent(const Json::Value& json_value) {
1620  std::string json_string = Utils::jsonToCanonicalStr(json_value);
1621  SQLite3Guard db = dbConnection();
1622  auto statement = db.prepareStatement<std::string>(
1623  "INSERT INTO report_events SELECT MAX(id) + 1, ? FROM report_events", json_string);
1624  if (statement.step() != SQLITE_DONE) {
1625  LOG_ERROR << "Can't save report event: " << db.errmsg();
1626  return;
1627  }
1628 }
1629 
1630 bool SQLStorage::loadReportEvents(Json::Value* report_array, int64_t* id_max) {
1631  SQLite3Guard db = dbConnection();
1632  auto statement = db.prepareStatement("SELECT id, json_string FROM report_events;");
1633  int statement_result = statement.step();
1634  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1635  LOG_ERROR << "Can't get report_events: " << db.errmsg();
1636  return false;
1637  }
1638  if (statement_result == SQLITE_DONE) {
1639  // if there are no any record in the DB
1640  return false;
1641  }
1642  *id_max = 0;
1643  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1644  try {
1645  int64_t id = statement.get_result_col_int(0);
1646  std::string json_string = statement.get_result_col_str(1).value();
1647  std::istringstream jss(json_string);
1648  Json::Value event_json;
1649  std::string errs;
1650  if (Json::parseFromStream(Json::CharReaderBuilder(), jss, &event_json, &errs)) {
1651  report_array->append(event_json);
1652  *id_max = (*id_max) > id ? (*id_max) : id;
1653  } else {
1654  LOG_ERROR << "Unable to parse event data: " << errs;
1655  }
1656  } catch (const boost::bad_optional_access&) {
1657  return false;
1658  }
1659  }
1660 
1661  return true;
1662 }
1663 
1664 void SQLStorage::deleteReportEvents(int64_t id_max) {
1665  SQLite3Guard db = dbConnection();
1666  if (!db.beginTransaction()) {
1667  LOG_ERROR << "Can't start transaction: " << db.errmsg();
1668  return;
1669  }
1670 
1671  auto statement = db.prepareStatement<int64_t>("DELETE FROM report_events WHERE id <= ?;", id_max);
1672  if (statement.step() != SQLITE_DONE) {
1673  LOG_ERROR << "Can't delete report_events";
1674  }
1675 
1676  db.commitTransaction();
1677 }
1678 
1679 void SQLStorage::clearInstallationResults() {
1680  SQLite3Guard db = dbConnection();
1681  if (!db.beginTransaction()) {
1682  LOG_ERROR << "Can't start transaction: " << db.errmsg();
1683  return;
1684  }
1685 
1686  if (db.exec("DELETE FROM device_installation_result;", nullptr, nullptr) != SQLITE_OK) {
1687  LOG_ERROR << "Can't clear device_installation_result: " << db.errmsg();
1688  return;
1689  }
1690 
1691  if (db.exec("DELETE FROM ecu_installation_results;", nullptr, nullptr) != SQLITE_OK) {
1692  LOG_ERROR << "Can't clear ecu_installation_results: " << db.errmsg();
1693  return;
1694  }
1695 
1696  db.commitTransaction();
1697 }
1698 
1699 bool SQLStorage::checkAvailableDiskSpace(const uint64_t required_bytes) const {
1700  struct statvfs stvfsbuf {};
1701  const int stat_res = statvfs(dbPath().c_str(), &stvfsbuf);
1702  if (stat_res < 0) {
1703  LOG_WARNING << "Unable to read filesystem statistics: error code " << stat_res;
1704  return true;
1705  }
1706  const uint64_t available_bytes = (static_cast<uint64_t>(stvfsbuf.f_bsize) * stvfsbuf.f_bavail);
1707  const uint64_t reserved_bytes = 1 << 20;
1708 
1709  if (required_bytes + reserved_bytes < available_bytes) {
1710  return true;
1711  } else {
1712  LOG_ERROR << "Insufficient disk space available to download target! Required: " << required_bytes
1713  << ", available: " << available_bytes << ", reserved: " << reserved_bytes;
1714  return false;
1715  }
1716 }
1717 
1718 boost::optional<std::pair<uintmax_t, std::string>> SQLStorage::checkTargetFile(const Uptane::Target& target) const {
1719  SQLite3Guard db = dbConnection();
1720 
1721  auto statement = db.prepareStatement<std::string>(
1722  "SELECT sha256, sha512, filename FROM target_images WHERE targetname = ?;", target.filename());
1723 
1724  int statement_state;
1725  while ((statement_state = statement.step()) == SQLITE_ROW) {
1726  auto sha256 = statement.get_result_col_str(0);
1727  auto sha512 = statement.get_result_col_str(1);
1728  auto filename = statement.get_result_col_str(2);
1729  if ((*sha256).empty() && (*sha512).empty()) {
1730  // Old aktualizr didn't save checksums, this could require to redownload old images.
1731  LOG_WARNING << "Image without checksum: " << target.filename();
1732  continue;
1733  }
1734  bool sha256_match = false;
1735  bool sha512_match = false;
1736  if (!(*sha256).empty()) {
1737  if (target.MatchHash(Uptane::Hash(Uptane::Hash::Type::kSha256, *sha256))) {
1738  sha256_match = true;
1739  }
1740  }
1741 
1742  if (!(*sha512).empty()) {
1743  if (target.MatchHash(Uptane::Hash(Uptane::Hash::Type::kSha512, *sha512))) {
1744  sha512_match = true;
1745  }
1746  }
1747  if (((*sha256).empty() || sha256_match) && ((*sha512).empty() || sha512_match)) {
1748  if (boost::filesystem::exists(images_path_ / *filename)) {
1749  return {{boost::filesystem::file_size(images_path_ / *filename), *filename}};
1750  } else {
1751  return boost::none;
1752  }
1753  }
1754  }
1755 
1756  if (statement_state == SQLITE_DONE) {
1757  return boost::none;
1758  }
1759  assert(statement_state != SQLITE_ROW); // from the previous loop precondition
1760  LOG_ERROR << "Statement step failure: " << db.errmsg();
1761 
1762  return boost::none;
1763 }
1764 
1766  public:
1767  SQLTargetWHandle(const SQLStorage& storage, Uptane::Target target)
1768  : db_path_(storage.dbPath()), target_(std::move(target)), storage_(&storage) {
1769  StorageTargetWHandle::WriteError exc("could not save file " + target_.filename() + " to the filesystem");
1770 
1771  std::string sha256Hash;
1772  std::string sha512Hash;
1773  for (const auto& hash : target_.hashes()) {
1774  if (hash.type() == Uptane::Hash::Type::kSha256) {
1775  sha256Hash = hash.HashString();
1776  } else if (hash.type() == Uptane::Hash::Type::kSha512) {
1777  sha512Hash = hash.HashString();
1778  }
1779  }
1780  std::string filename = (storage.images_path_ / target_.hashes()[0].HashString()).string();
1781  SQLite3Guard db = storage_->dbConnection();
1782  auto statement = db.prepareStatement<std::string, std::string, std::string>(
1783  "INSERT OR REPLACE INTO target_images (targetname, sha256, sha512, filename) VALUES ( ?, ?, ?, ?);",
1784  target_.filename(), sha256Hash, sha512Hash, target_.hashes()[0].HashString());
1785 
1786  if (statement.step() != SQLITE_DONE) {
1787  LOG_ERROR << "Statement step failure: " << db.errmsg();
1788  throw exc;
1789  }
1790  boost::filesystem::create_directories(storage.images_path_);
1791  stream_.open(filename);
1792  if (!stream_.good()) {
1793  LOG_ERROR << "Could not open image for write: " << storage.images_path_ / target_.filename();
1794  throw exc;
1795  }
1796  }
1797 
1798  ~SQLTargetWHandle() override {
1799  try {
1800  SQLTargetWHandle::wcommit();
1801  } catch (std::exception& ex) {
1802  LOG_ERROR << "Failed to commit to database: " << ex.what();
1803  } catch (...) {
1804  LOG_ERROR << "Failed to commit to database: unknown error";
1805  }
1806  }
1807 
1808  size_t wfeed(const uint8_t* buf, size_t size) override {
1809  stream_.write(reinterpret_cast<const char*>(buf), static_cast<std::streamsize>(size));
1810  written_size_ += size;
1811 
1812  return size;
1813  }
1814 
1815  void wcommit() override {
1816  if (stream_) {
1817  stream_.close();
1818  }
1819  }
1820 
1821  void wabort() noexcept override {
1822  if (stream_) {
1823  stream_.close();
1824  }
1825 
1826  if (storage_ != nullptr) {
1827  SQLite3Guard db = storage_->dbConnection();
1828  auto statement =
1829  db.prepareStatement<std::string>("DELETE FROM target_images WHERE targetname=?;", target_.filename());
1830  if (statement.step() != SQLITE_DONE) {
1831  LOG_ERROR << "could not delete " << target_.filename() << " from sql storage";
1832  }
1833  }
1834  }
1835 
1836  friend class SQLTargetRHandle;
1837 
1838  private:
1839  SQLTargetWHandle(const boost::filesystem::path& db_path, Uptane::Target target,
1840  const boost::filesystem::path& image_path, const uintmax_t& start_from = 0)
1841  : db_path_(db_path), target_(std::move(target)) {
1842  stream_.open(image_path.string(), std::ofstream::out | std::ofstream::app);
1843  if (!stream_.good()) {
1844  LOG_ERROR << "Could not open image for write: " << image_path;
1845  throw StorageTargetWHandle::WriteError("could not open file for write: " + image_path.string());
1846  }
1847 
1848  written_size_ = start_from;
1849  }
1850  boost::filesystem::path db_path_;
1851  Uptane::Target target_;
1852  std::ofstream stream_;
1853  const SQLStorage* storage_ = nullptr;
1854 };
1855 
1856 std::unique_ptr<StorageTargetWHandle> SQLStorage::allocateTargetFile(const Uptane::Target& target) {
1857  return std::unique_ptr<StorageTargetWHandle>(new SQLTargetWHandle(*this, target));
1858 }
1859 
1861  public:
1862  SQLTargetRHandle(const SQLStorage& storage, Uptane::Target target)
1863  : db_path_(storage.dbPath()), target_(std::move(target)), size_(0) {
1864  StorageTargetRHandle::ReadError exc("could not read file " + target_.filename() + " from sql storage");
1865 
1866  auto exists = storage.checkTargetFile(target_);
1867  if (!exists) {
1868  LOG_ERROR << "File " << target_.filename() << " with expected hash not found in the database!";
1869  throw exc;
1870  }
1871 
1872  size_ = exists->first;
1873  partial_ = size_ < target_.length();
1874  image_path_ = storage.images_path_ / exists->second;
1875  stream_.open(image_path_.string());
1876  if (!stream_.good()) {
1877  LOG_ERROR << "Could not open image: " << storage.images_path_ / target_.filename();
1878  throw exc;
1879  }
1880  }
1881 
1882  ~SQLTargetRHandle() override { SQLTargetRHandle::rclose(); }
1883 
1884  uintmax_t rsize() const override { return size_; }
1885 
1886  size_t rread(uint8_t* buf, size_t size) override {
1887  stream_.read(reinterpret_cast<char*>(buf), static_cast<std::streamsize>(size));
1888  return static_cast<size_t>(stream_.gcount());
1889  }
1890 
1891  void rclose() noexcept override {
1892  if (stream_.is_open()) {
1893  stream_.close();
1894  }
1895  }
1896 
1897  bool isPartial() const noexcept override { return partial_; }
1898  std::unique_ptr<StorageTargetWHandle> toWriteHandle() override {
1899  return std::unique_ptr<StorageTargetWHandle>(new SQLTargetWHandle(db_path_, target_, image_path_, size_));
1900  }
1901 
1902  private:
1903  boost::filesystem::path db_path_;
1904  Uptane::Target target_;
1905  uintmax_t size_;
1906  bool partial_{false};
1907  boost::filesystem::path image_path_;
1908  std::ifstream stream_;
1909 };
1910 
1911 std::unique_ptr<StorageTargetRHandle> SQLStorage::openTargetFile(const Uptane::Target& target) {
1912  return std_::make_unique<SQLTargetRHandle>(*this, target);
1913 }
1914 
1915 std::vector<Uptane::Target> SQLStorage::getTargetFiles() {
1916  SQLite3Guard db = dbConnection();
1917 
1918  auto statement = db.prepareStatement<>("SELECT targetname, filename, sha256, sha512 FROM target_images;");
1919 
1920  std::vector<Uptane::Target> v;
1921 
1922  int result = statement.step();
1923  while (result != SQLITE_DONE) {
1924  if (result != SQLITE_ROW) {
1925  LOG_ERROR << "Statement step failure: " << db.errmsg();
1926  throw std::runtime_error("Error getting target files");
1927  }
1928 
1929  auto tname = statement.get_result_col_str(0).value();
1930  auto fname = statement.get_result_col_str(1).value();
1931  auto tsize = boost::filesystem::file_size(images_path_ / fname);
1932  auto sha256 = statement.get_result_col_str(2).value();
1933  auto sha512 = statement.get_result_col_str(3).value();
1934 
1935  std::vector<Uptane::Hash> hashes;
1936  if (!sha256.empty()) {
1937  hashes.emplace_back(Uptane::Hash::Type::kSha256, sha256);
1938  }
1939  if (!sha512.empty()) {
1940  hashes.emplace_back(Uptane::Hash::Type::kSha512, sha512);
1941  }
1942  v.emplace_back(tname, Uptane::EcuMap{}, hashes, tsize);
1943 
1944  result = statement.step();
1945  }
1946 
1947  return v;
1948 }
1949 
1950 void SQLStorage::removeTargetFile(const std::string& target_name) {
1951  SQLite3Guard db = dbConnection();
1952 
1953  if (!db.beginTransaction()) {
1954  LOG_ERROR << "Can't start transaction: " << db.errmsg();
1955  return;
1956  }
1957 
1958  auto statement =
1959  db.prepareStatement<std::string>("SELECT filename FROM target_images WHERE targetname = ?;", target_name);
1960 
1961  if (statement.step() != SQLITE_ROW) {
1962  LOG_ERROR << "Statement step failure: " << db.errmsg();
1963  throw std::runtime_error("Could not find target file");
1964  }
1965 
1966  std::string filename = statement.get_result_col_str(0).value();
1967 
1968  statement = db.prepareStatement<std::string>("DELETE FROM target_images WHERE targetname=?;", target_name);
1969 
1970  if (statement.step() != SQLITE_DONE) {
1971  LOG_ERROR << "Statement step failure: " << db.errmsg();
1972  throw std::runtime_error("Could not remove target file");
1973  }
1974  try {
1975  boost::filesystem::remove(images_path_ / filename);
1976  } catch (std::exception& e) {
1977  LOG_ERROR << "Could not remove target file";
1978  throw;
1979  }
1980 
1981  db.commitTransaction();
1982 }
1983 
1984 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:55
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:1860
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:1765
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