2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "upgrader.hh"
28 #include <sys/smack.h>
31 #include <sys/types.h>
35 #include <tzplatform_config.h>
38 #include "pkg_upgrader_factory.hh"
41 using std::shared_ptr;
43 using std::unique_ptr;
46 constexpr char kLogFileName[] = "/var/log/appfw/app-installers/fota.log";
47 constexpr int kLogRotationSize = 1024 * 1024; // 1MB
48 constexpr int kLogMaximumRotation = 3;
49 constexpr int kBufSize = 1024;
50 constexpr char kDbLabel[] = "User::Home";
51 constexpr char kAppfwUser[] = "app_fw";
55 explicit File(const string& path) {
56 fd_ = open(path.c_str(), O_RDONLY);
59 File(const string& path, int flags, mode_t mode) {
60 fd_ = open(path.c_str(), flags, mode);
72 int FStat(struct stat* statbuf) {
73 return fstat(fd_, statbuf);
76 int FChOwn(uid_t owner, gid_t group) {
77 return fchown(fd_, owner, group);
80 int FChMod(mode_t mode) {
81 return fchmod(fd_, mode);
94 namespace common_fota {
96 Upgrader::Upgrader() {
97 logger_ = shared_ptr<utils::FileLogBackend>(new utils::FileLogBackend(
98 ::kLogFileName, ::kLogRotationSize, ::kLogMaximumRotation));
99 ::utils::LogCore::GetCore().AddLogBackend(logger_);
100 string path = tzplatform_getenv(TZ_SYS_DB);
104 void Upgrader::SetDbPath(const string& path) {
105 parser_db_ = path + "/.pkgmgr_parser.db";
106 cert_db_ = path + "/.pkgmgr_cert.db";
109 bool Upgrader::Process(PkgFinder* finder) {
110 if (CheckAndRestoreBackupDbs() != 0) {
111 LOG(ERROR) << "CheckAndRestoreBackupDbs failed";
115 if (MakeBackupDbs() != 0) {
116 LOG(ERROR) << "MakeBackupDbs failed";
120 // set the database permission to solve the case of using the backup database
121 // which the smack label is not applied properly
122 if (SetDbPermission(parser_db_) != 0) {
123 LOG(ERROR) << "SetDbPermission at parser_db failed";
127 if (SetDbPermission(cert_db_) != 0) {
128 LOG(ERROR) << "SetDbPermission at cert_db failed";
132 PkgUpgraderFactory factory;
133 auto list = factory.MakeList(finder);
135 for (auto& pkg : list) {
136 if (pkg->Upgrade()) {
137 LOG(DEBUG) << "upgrade success (" << pkg->GetId() << ")";
138 success_list_.push_back(move(pkg));
140 LOG(ERROR) << "upgrade failed (" << pkg->GetId() << ")";
141 failure_list_.push_back(move(pkg));
147 logger_->WriteLog(::utils::LogLevel::LOG_INFO, "", "Upgrade Done");
148 logger_->WriteLogToFile();
152 const list<unique_ptr<PkgUpgrader>>& Upgrader::GetSuccessList() const {
153 return success_list_;
156 const list<unique_ptr<PkgUpgrader>>& Upgrader::GetFailureList() const {
157 return failure_list_;
160 int Upgrader::CheckAndRestoreBackupDbs() {
161 // if backup flag exists, it means the previous backup process aborted.
162 if (CheckBackupFlag(parser_db_) == 0 || CheckBackupFlag(cert_db_) == 0) {
164 RemoveBackupFlag(parser_db_);
165 RemoveBackupFlag(cert_db_);
169 if (IntegrityCheckBackupDbs()) {
174 if (CheckAndRestoreBackup(parser_db_))
177 if (CheckAndRestoreBackup(cert_db_))
183 int Upgrader::CheckAndRestoreBackup(const string& origin_path) {
184 string backup_path = origin_path + ".bck";
185 string journal_path = origin_path + "-journal";
186 string journal_backup_path = origin_path + ".bck-journal";
188 if (access(backup_path.c_str(), F_OK))
191 if (access(journal_backup_path.c_str(), F_OK) == 0) {
192 if (rename(journal_backup_path.c_str(), journal_path.c_str())) {
193 LOG(ERROR) << "fail to rename " << journal_backup_path
194 << " to " << journal_path << " " << errno;
199 if (rename(backup_path.c_str(), origin_path.c_str())) {
200 LOG(ERROR) << "fail to rename " << backup_path
201 << " to " << origin_path << " " << errno;
208 int Upgrader::IntegrityCheckBackupDbs() {
209 std::string parser_db_bck = parser_db_ + ".bck";
210 std::string cert_db_bck = cert_db_ + ".bck";
212 if (IntegrityCheck(parser_db_bck) != 0) {
213 LOG(ERROR) << "Fail to integrity check db(" << parser_db_bck << "%s)";
217 if (IntegrityCheck(cert_db_bck) != 0) {
218 LOG(ERROR) << "Fail to integrity check db(" << cert_db_bck << "%s)";
225 int Upgrader::IntegrityCheck(const std::string& path) {
226 constexpr const char query[] = "PRAGMA integrity_check";
230 if (access(path.c_str(), F_OK))
233 if (sqlite3_open_v2(path.c_str(), &db,
234 SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) {
235 LOG(ERROR) << "Fail to open (" << path << ") db handle";
238 unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
239 db_auto(db, sqlite3_close_v2);
241 if (sqlite3_prepare_v2(db, query, strlen(query),
242 &stmt, nullptr) != SQLITE_OK) {
243 LOG(ERROR) << "prepare failed : " << sqlite3_errmsg(db);
246 unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*>
247 stmt_auto(stmt, sqlite3_finalize);
249 if (sqlite3_step(stmt) != SQLITE_ROW) {
250 LOG(ERROR) << "sqlite3_step fail";
254 std::string val = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
256 LOG(ERROR) << "Fail to integrity check, db("
257 << path << "), val(" << val << ")";
264 int Upgrader::SetDbPermission(const string& path) {
267 struct passwd* result;
270 int ret = getpwnam_r(kAppfwUser, &pwd, buf, sizeof(buf), &result);
271 if (result == nullptr) {
272 LOG(ERROR) << "getpwnam_r failed: " << errno;
275 uid_t uid = pwd.pw_uid;
277 ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
278 if (result == nullptr) {
279 LOG(ERROR) << "getpwuid_r failed: " << errno;
283 for (const auto& p : std::vector<std::string>{path, path + "-journal"}) {
286 if (file.GetFd() == -1) {
287 LOG(ERROR) << "open(" << p << "failed: " << errno;
291 ret = file.FStat(&sb);
293 LOG(ERROR) << "stat " << p << "failed: " << errno;
296 if (S_ISLNK(sb.st_mode)) {
297 LOG(ERROR) << p << " is symlink!";
300 ret = file.FChOwn(uid, pwd.pw_gid);
302 LOG(ERROR) << "fchown " << p << " failed: " << errno;
306 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
307 if (p.find(cert_db_) != string::npos)
309 ret = file.FChMod(mode);
311 LOG(ERROR) << "fchmod " << p << " failed: " << errno;
315 if (smack_setlabel(p.c_str(), kDbLabel, SMACK_LABEL_ACCESS))
316 LOG(ERROR) << "failed chsmack -a " << kDbLabel << " " << path;
322 int Upgrader::CreateBackupFlag(const string& path) {
323 string flag = path + ".bck.flag";
325 ::File file(flag, O_CREAT | O_WRONLY, 0644);
326 if (file.GetFd() == -1) {
327 LOG(ERROR) << "failed to create flag file " << flag << ", " << errno;
334 int Upgrader::CheckBackupFlag(const string& path) {
335 string flag = path + ".bck.flag";
337 if (access(flag.c_str(), F_OK) != 0)
343 int Upgrader::RemoveBackupFlag(const string& path) {
344 string flag = path + ".bck.flag";
346 if (remove(flag.c_str())) {
347 LOG(ERROR) << "cannot remove flag file(" << flag << ") " << errno;
354 int Upgrader::BackupFile(const string& src_path, const string& dest_path) {
358 sqlite3_backup* p_backup;
360 if (access(src_path.c_str(), F_OK) != 0) {
361 LOG(ERROR) << "File(" << src_path << ") is not exist";
365 if (CreateBackupFlag(src_path)) {
366 LOG(ERROR) << "failed to create backup flag";
370 if (sqlite3_open_v2(src_path.c_str(), &src_db,
371 SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) {
372 LOG(ERROR) << "Failed to open ( "
373 << src_path << ") db handle : " << src_path;
376 unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
377 src_db_auto(src_db, sqlite3_close_v2);
379 if (sqlite3_open_v2(dest_path.c_str(), &dest_db,
380 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) {
381 LOG(ERROR) << "Failed to open ( "
382 << dest_path << ") db handle : " << dest_path;
385 unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
386 dest_db_auto(dest_db, sqlite3_close_v2);
388 p_backup = sqlite3_backup_init(dest_db, "main", src_db, "main");
391 ret = sqlite3_backup_step(p_backup, -1);
392 if (ret == SQLITE_BUSY || ret == SQLITE_LOCKED)
394 } while (ret == SQLITE_OK || ret == SQLITE_BUSY
395 || ret == SQLITE_LOCKED);
397 sqlite3_backup_finish(p_backup);
400 ret = sqlite3_errcode(dest_db);
401 if (ret != SQLITE_OK) {
402 LOG(ERROR) << "Fail to backup db val(" << ret << ")";
406 if (SetDbPermission(dest_path) != 0)
409 RemoveBackupFlag(src_path);
414 int Upgrader::BackupDb(const string& src_path, const string& dest_path) {
415 if (BackupFile(src_path, dest_path) != 0)
421 int Upgrader::MakeBackupDbs() {
422 string parser_db_bck = parser_db_ + ".bck";
423 string cert_db_bck = cert_db_ + ".bck";
425 if (BackupDb(parser_db_, parser_db_bck) == -1) {
426 LOG(ERROR) << "Fail to backup [" << parser_db_ <<
427 "] to [" << parser_db_bck << "]";
432 if (BackupDb(cert_db_, cert_db_bck) == -1) {
433 LOG(ERROR) << "Fail to backup [" << cert_db_ << "] to [" <<
442 void Upgrader::RemoveBackupPath(const string& origin_path) {
443 string backup_path = origin_path + ".bck";
444 string journal_backup_path = origin_path + ".bck-journal";
446 if (access(backup_path.c_str(), F_OK) == 0 && remove(backup_path.c_str()))
447 LOG(ERROR) << "cannot remove backup file(" << backup_path << ") " << errno;
449 if (access(journal_backup_path.c_str(), F_OK) == 0
450 && remove(journal_backup_path.c_str()))
451 LOG(ERROR) << "cannot remove backup file("
452 << journal_backup_path << ") " << errno;
455 void Upgrader::RemoveBackupDbs() {
456 RemoveBackupPath(parser_db_);
457 RemoveBackupPath(cert_db_);
460 } // namespace common_fota