1 // Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
5 #include <boost/exception/diagnostic_information.hpp>
6 #include <boost/filesystem/operations.hpp>
7 #include <boost/filesystem/path.hpp>
10 #include <common/utils/file_util.h>
11 #include <common/utils/request.h>
12 #include <common/utils/subprocess.h>
13 #include <common/utils/user_util.h>
14 #include <manifest_parser/utils/logging.h>
15 #include <sys/types.h>
16 #include <tzplatform_config.h>
23 namespace bf = boost::filesystem;
24 namespace ci = common_installer;
28 typedef std::pair<std::string, std::string> RecoverEntry;
30 const char kRecoveryFilePattern[] = "^(.*)-recovery-(.){6}$";
31 const char kBackupFilePattern[] = "^(.*)-recovery-(.){6}\\.bck$";
32 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
34 std::string TruncateNewLine(const char* data) {
35 int length = strlen(data);
36 if (data[length - 1] == '\n')
38 return std::string(data, length);
41 std::vector<std::string> ParseRecoveryFile(const char* file) {
42 FILE* handle = fopen(file, "r");
44 LOG(ERROR) << "Failed to open recovery file :" << file;
48 std::vector<std::string> arguments;
49 std::array<char, 200> data;
51 while (fgets(data.data(), data.size(), handle)) {
52 std::string line_data = TruncateNewLine(data.data());
53 if (line_data == "cleanup") {
54 arguments.emplace_back("--recovery-cleanup");
58 if (!boost::filesystem::exists(line_data))
61 arguments.emplace_back(line_data);
68 class PkgRecoveryService {
71 ~PkgRecoveryService();
75 void SearchBackupFiles(uid_t uid);
76 std::vector<RecoverEntry> SearchRecoveryFiles(uid_t uid);
77 void ProcessRecovery(uid_t uid, const std::vector<RecoverEntry>& entries);
78 bool RunBackend(uid_t uid, const char* type, const char* file);
81 PkgRecoveryService::PkgRecoveryService() {
84 PkgRecoveryService::~PkgRecoveryService() {
87 bool PkgRecoveryService::RunBackend(uid_t uid, const char* type,
89 std::string backend_cmd = "/usr/bin/" + std::string(type) + "-backend";
90 ci::Subprocess backend(backend_cmd);
91 std::string str_uid = std::to_string(uid);
92 if (std::string(type) == "unified") {
93 auto arguments = ParseRecoveryFile(file);
94 if (!arguments.size())
95 return ci::Remove(bf::path(file));
97 arguments.emplace(arguments.begin(), "-b");
98 arguments.emplace_back("-u");
99 arguments.emplace_back(str_uid.c_str());
101 backend.RunWithArgs(arguments);
103 backend.Run("-b", file, "-u", str_uid.c_str());
105 int status = backend.Wait();
106 if (WIFSIGNALED(status) || WEXITSTATUS(status))
109 ci::Remove(bf::path(file));
114 void PkgRecoveryService::Run() {
115 // recover global packages
116 SearchBackupFiles(kGlobalUserUid);
117 LOG(INFO) << "Searching recovery files for user " << kGlobalUserUid;
118 std::vector<RecoverEntry> globalentries = SearchRecoveryFiles(kGlobalUserUid);
119 ProcessRecovery(kGlobalUserUid, globalentries);
121 // recover normal user packages
122 ci::UserList list = ci::GetUserList();
123 for (auto userinfo : list) {
124 uid_t uid = std::get<0>(userinfo);
125 LOG(INFO) << "Searching recovery files for user " << std::get<0>(userinfo);
126 SearchBackupFiles(uid);
127 std::vector<RecoverEntry> entries = SearchRecoveryFiles(uid);
128 ProcessRecovery(uid, entries);
132 void PkgRecoveryService::SearchBackupFiles(uid_t uid) {
133 const bf::path recovery_dir = ci::GetRootAppPath(false, uid);
135 for (bf::directory_iterator iter(recovery_dir);
136 iter != bf::directory_iterator();
138 std::string file = iter->path().filename().string();
139 std::regex backup_regex(kBackupFilePattern);
141 if (std::regex_search(file, match, backup_regex)) {
142 bf::path orig_file(iter->path().parent_path() / iter->path().stem());
143 if (bf::exists(orig_file))
144 bf::remove(orig_file);
145 bf::rename(iter->path(), orig_file);
149 LOG(WARNING) << "Exception occurred: "
150 << boost::current_exception_diagnostic_information();
154 std::vector<RecoverEntry> PkgRecoveryService::SearchRecoveryFiles(uid_t uid) {
155 std::vector<RecoverEntry> list;
156 const bf::path recovery_dir = ci::GetRootAppPath(false, uid);
157 LOG(INFO) << "RootAppPath: " << recovery_dir;
158 for (bf::directory_iterator iter(recovery_dir);
159 iter != bf::directory_iterator();
162 std::string file = iter->path().filename().string();
163 std::regex recovery_regex(kRecoveryFilePattern);
165 if (std::regex_search(file, match, recovery_regex)) {
166 LOG(INFO) << "Found recovery file: " << file;
167 std::string type(match[1]);
168 if (type == "unified")
169 list.emplace(list.begin(), type, iter->path().string());
171 list.emplace_back(type, iter->path().string());
174 LOG(WARNING) << "Exception occurred: "
175 << boost::current_exception_diagnostic_information();
183 void PkgRecoveryService::ProcessRecovery(uid_t uid,
184 const std::vector<RecoverEntry>& entries) {
185 LOG(INFO) << "Process recovery for user " << uid;
186 for (auto entry : entries) {
187 const char* type = entry.first.c_str();
188 const char* file = entry.second.c_str();
189 if (!bf::exists(file))
192 if (!RunBackend(uid, type, file))
193 LOG(ERROR) << "Recovery process for " << file << " failed";
201 PkgRecoveryService service;
205 LOG(ERROR) << "Exception occured";