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);
134 if (factory.IsFailed()) {
139 for (auto& pkg : list) {
140 if (pkg->Upgrade()) {
141 LOG(DEBUG) << "upgrade success (" << pkg->GetId() << ")";
142 success_list_.push_back(move(pkg));
144 LOG(ERROR) << "upgrade failed (" << pkg->GetId() << ")";
145 failure_list_.push_back(move(pkg));
151 logger_->WriteLog(::utils::LogLevel::LOG_INFO, "", "Upgrade Done");
152 logger_->WriteLogToFile();
156 const list<unique_ptr<PkgUpgrader>>& Upgrader::GetSuccessList() const {
157 return success_list_;
160 const list<unique_ptr<PkgUpgrader>>& Upgrader::GetFailureList() const {
161 return failure_list_;
164 int Upgrader::CheckAndRestoreBackupDbs() {
165 // if backup flag exists, it means the previous backup process aborted.
166 if (CheckBackupFlag(parser_db_) == 0 || CheckBackupFlag(cert_db_) == 0) {
168 RemoveBackupFlag(parser_db_);
169 RemoveBackupFlag(cert_db_);
173 if (IntegrityCheckBackupDbs()) {
178 if (CheckAndRestoreBackup(parser_db_))
181 if (CheckAndRestoreBackup(cert_db_))
187 int Upgrader::CheckAndRestoreBackup(const string& origin_path) {
188 string backup_path = origin_path + ".bck";
189 string journal_path = origin_path + "-journal";
190 string journal_backup_path = origin_path + ".bck-journal";
192 if (access(backup_path.c_str(), F_OK))
195 if (access(journal_backup_path.c_str(), F_OK) == 0) {
196 if (rename(journal_backup_path.c_str(), journal_path.c_str())) {
197 LOG(ERROR) << "fail to rename " << journal_backup_path
198 << " to " << journal_path << " " << errno;
203 if (rename(backup_path.c_str(), origin_path.c_str())) {
204 LOG(ERROR) << "fail to rename " << backup_path
205 << " to " << origin_path << " " << errno;
212 int Upgrader::IntegrityCheckBackupDbs() {
213 std::string parser_db_bck = parser_db_ + ".bck";
214 std::string cert_db_bck = cert_db_ + ".bck";
216 if (IntegrityCheck(parser_db_bck) != 0) {
217 LOG(ERROR) << "Fail to integrity check db(" << parser_db_bck << "%s)";
221 if (IntegrityCheck(cert_db_bck) != 0) {
222 LOG(ERROR) << "Fail to integrity check db(" << cert_db_bck << "%s)";
229 int Upgrader::IntegrityCheck(const std::string& path) {
230 constexpr const char query[] = "PRAGMA integrity_check";
234 if (access(path.c_str(), F_OK))
237 if (sqlite3_open_v2(path.c_str(), &db,
238 SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) {
239 LOG(ERROR) << "Fail to open (" << path << ") db handle";
242 unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
243 db_auto(db, sqlite3_close_v2);
245 if (sqlite3_prepare_v2(db, query, strlen(query),
246 &stmt, nullptr) != SQLITE_OK) {
247 LOG(ERROR) << "prepare failed : " << sqlite3_errmsg(db);
250 unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*>
251 stmt_auto(stmt, sqlite3_finalize);
253 if (sqlite3_step(stmt) != SQLITE_ROW) {
254 LOG(ERROR) << "sqlite3_step fail";
258 std::string val = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
260 LOG(ERROR) << "Fail to integrity check, db("
261 << path << "), val(" << val << ")";
268 int Upgrader::SetDbPermission(const string& path) {
271 struct passwd* result;
274 int ret = getpwnam_r(kAppfwUser, &pwd, buf, sizeof(buf), &result);
275 if (result == nullptr) {
276 LOG(ERROR) << "getpwnam_r failed: " << errno;
279 uid_t uid = pwd.pw_uid;
281 ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
282 if (result == nullptr) {
283 LOG(ERROR) << "getpwuid_r failed: " << errno;
287 for (const auto& p : std::vector<std::string>{path, path + "-journal"}) {
290 if (file.GetFd() == -1) {
291 LOG(ERROR) << "open(" << p << "failed: " << errno;
295 ret = file.FStat(&sb);
297 LOG(ERROR) << "stat " << p << "failed: " << errno;
300 if (S_ISLNK(sb.st_mode)) {
301 LOG(ERROR) << p << " is symlink!";
304 ret = file.FChOwn(uid, pwd.pw_gid);
306 LOG(ERROR) << "fchown " << p << " failed: " << errno;
310 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
311 if (p.find(cert_db_) != string::npos)
313 ret = file.FChMod(mode);
315 LOG(ERROR) << "fchmod " << p << " failed: " << errno;
319 if (smack_setlabel(p.c_str(), kDbLabel, SMACK_LABEL_ACCESS)) {
320 LOG(ERROR) << "failed chsmack -a " << kDbLabel << " " << path;
328 int Upgrader::CreateBackupFlag(const string& path) {
329 string flag = path + ".bck.flag";
331 ::File file(flag, O_CREAT | O_WRONLY, 0644);
332 if (file.GetFd() == -1) {
333 LOG(ERROR) << "failed to create flag file " << flag << ", " << errno;
341 int Upgrader::CheckBackupFlag(const string& path) {
342 string flag = path + ".bck.flag";
344 if (access(flag.c_str(), F_OK) != 0)
350 int Upgrader::RemoveBackupFlag(const string& path) {
351 string flag = path + ".bck.flag";
353 if (remove(flag.c_str())) {
354 LOG(ERROR) << "cannot remove flag file(" << flag << ") " << errno;
361 int Upgrader::BackupFile(const string& src_path, const string& dest_path) {
365 sqlite3_backup* p_backup;
367 if (access(src_path.c_str(), F_OK) != 0) {
368 LOG(ERROR) << "File(" << src_path << ") is not exist";
372 if (CreateBackupFlag(src_path)) {
373 LOG(ERROR) << "failed to create backup flag";
377 if (sqlite3_open_v2(src_path.c_str(), &src_db,
378 SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) {
379 LOG(ERROR) << "Failed to open ( "
380 << src_path << ") db handle : " << src_path;
383 unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
384 src_db_auto(src_db, sqlite3_close_v2);
386 if (sqlite3_open_v2(dest_path.c_str(), &dest_db,
387 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) {
388 LOG(ERROR) << "Failed to open ( "
389 << dest_path << ") db handle : " << dest_path;
392 unique_ptr<sqlite3, decltype(sqlite3_close_v2)*>
393 dest_db_auto(dest_db, sqlite3_close_v2);
395 p_backup = sqlite3_backup_init(dest_db, "main", src_db, "main");
398 ret = sqlite3_backup_step(p_backup, -1);
399 if (ret == SQLITE_BUSY || ret == SQLITE_LOCKED)
401 } while (ret == SQLITE_OK || ret == SQLITE_BUSY
402 || ret == SQLITE_LOCKED);
404 sqlite3_backup_finish(p_backup);
407 ret = sqlite3_errcode(dest_db);
408 if (ret != SQLITE_OK) {
409 LOG(ERROR) << "Fail to backup db val(" << ret << ")";
413 if (SetDbPermission(dest_path) != 0)
416 RemoveBackupFlag(src_path);
421 int Upgrader::BackupDb(const string& src_path, const string& dest_path) {
422 if (BackupFile(src_path, dest_path) != 0)
428 int Upgrader::MakeBackupDbs() {
429 string parser_db_bck = parser_db_ + ".bck";
430 string cert_db_bck = cert_db_ + ".bck";
432 if (BackupDb(parser_db_, parser_db_bck) == -1) {
433 LOG(ERROR) << "Fail to backup [" << parser_db_ <<
434 "] to [" << parser_db_bck << "]";
439 if (BackupDb(cert_db_, cert_db_bck) == -1) {
440 LOG(ERROR) << "Fail to backup [" << cert_db_ << "] to [" <<
449 void Upgrader::RemoveBackupPath(const string& origin_path) {
450 string backup_path = origin_path + ".bck";
451 string journal_backup_path = origin_path + ".bck-journal";
453 if (access(backup_path.c_str(), F_OK) == 0 && remove(backup_path.c_str()))
454 LOG(ERROR) << "cannot remove backup file(" << backup_path << ") " << errno;
456 if (access(journal_backup_path.c_str(), F_OK) == 0
457 && remove(journal_backup_path.c_str()))
458 LOG(ERROR) << "cannot remove backup file("
459 << journal_backup_path << ") " << errno;
462 void Upgrader::RemoveBackupDbs() {
463 RemoveBackupPath(parser_db_);
464 RemoveBackupPath(cert_db_);
467 } // namespace common_fota