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.
6 #include <common/utils/file_util.h>
7 #include <common/utils/request.h>
8 #include <common/utils/subprocess.h>
9 #include <common/utils/user_util.h>
10 #include <manifest_parser/utils/logging.h>
11 #include <sys/types.h>
12 #include <tzplatform_config.h>
21 namespace ci = common_installer;
22 namespace fs = std::filesystem;
26 typedef std::pair<std::string, std::string> RecoverEntry;
28 const char kRecoveryFilePattern[] = "^(.*)-recovery-(.){6}$";
29 const char kBackupFilePattern[] = "^(.*)-recovery-(.){6}\\.bck$";
30 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
32 std::string TruncateNewLine(const char* data) {
33 int length = strlen(data);
34 if (data[length - 1] == '\n')
36 return std::string(data, length);
39 std::vector<std::string> ParseRecoveryFile(const char* file) {
40 FILE* handle = fopen(file, "r");
42 LOG(ERROR) << "Failed to open recovery file :" << file;
46 std::vector<std::string> arguments;
47 std::array<char, 200> data;
49 while (fgets(data.data(), data.size(), handle)) {
50 std::string line_data = TruncateNewLine(data.data());
51 if (line_data == "cleanup") {
52 arguments.emplace_back("--recovery-cleanup");
56 if (!std::filesystem::exists(line_data))
59 arguments.emplace_back(line_data);
66 class PkgRecoveryService {
69 ~PkgRecoveryService();
73 void SearchBackupFiles(uid_t uid);
74 std::vector<RecoverEntry> SearchRecoveryFiles(uid_t uid);
75 void ProcessRecovery(uid_t uid, const std::vector<RecoverEntry>& entries);
76 bool RunBackend(uid_t uid, const char* type, const char* file);
79 PkgRecoveryService::PkgRecoveryService() {
82 PkgRecoveryService::~PkgRecoveryService() {
85 bool PkgRecoveryService::RunBackend(uid_t uid, const char* type,
87 std::string backend_cmd = "/usr/bin/" + std::string(type) + "-backend";
88 ci::Subprocess backend(backend_cmd);
89 std::string str_uid = std::to_string(uid);
90 if (std::string(type) == "unified") {
91 auto arguments = ParseRecoveryFile(file);
92 if (!arguments.size())
93 return ci::Remove(fs::path(file));
95 arguments.emplace(arguments.begin(), "-b");
96 arguments.emplace_back("-u");
97 arguments.emplace_back(str_uid.c_str());
99 backend.RunWithArgs(arguments);
101 backend.Run("-b", file, "-u", str_uid.c_str());
103 int status = backend.Wait();
104 if (WIFSIGNALED(status) || WEXITSTATUS(status))
107 ci::Remove(fs::path(file));
112 void PkgRecoveryService::Run() {
113 // recover global packages
114 SearchBackupFiles(kGlobalUserUid);
115 LOG(INFO) << "Searching recovery files for user " << kGlobalUserUid;
116 std::vector<RecoverEntry> globalentries = SearchRecoveryFiles(kGlobalUserUid);
117 ProcessRecovery(kGlobalUserUid, globalentries);
119 // recover normal user packages
120 ci::UserList list = ci::GetUserList();
121 for (const auto& userinfo : list) {
122 uid_t uid = std::get<0>(userinfo);
123 LOG(INFO) << "Searching recovery files for user " << std::get<0>(userinfo);
124 SearchBackupFiles(uid);
125 std::vector<RecoverEntry> entries = SearchRecoveryFiles(uid);
126 ProcessRecovery(uid, entries);
130 void PkgRecoveryService::SearchBackupFiles(uid_t uid) {
131 const fs::path recovery_dir = ci::GetRootAppPath(false, uid);
133 for (fs::directory_iterator iter(recovery_dir);
134 iter != fs::directory_iterator();
136 std::string file = iter->path().filename().string();
137 std::regex backup_regex(kBackupFilePattern);
139 if (std::regex_search(file, match, backup_regex)) {
140 fs::path orig_file(iter->path().parent_path() / iter->path().stem());
141 if (fs::exists(orig_file))
142 fs::remove(orig_file);
143 fs::rename(iter->path(), orig_file);
146 } catch (const std::exception& e) {
147 LOG(WARNING) << "Exception occurred: "
148 << typeid(e).name() << ", " << e.what();
152 std::vector<RecoverEntry> PkgRecoveryService::SearchRecoveryFiles(uid_t uid) {
153 std::vector<RecoverEntry> list;
154 const fs::path recovery_dir = ci::GetRootAppPath(false, uid);
155 LOG(INFO) << "RootAppPath: " << recovery_dir;
156 for (fs::directory_iterator iter(recovery_dir);
157 iter != fs::directory_iterator();
160 std::string file = iter->path().filename().string();
161 std::regex recovery_regex(kRecoveryFilePattern);
163 if (std::regex_search(file, match, recovery_regex)) {
164 LOG(INFO) << "Found recovery file: " << file;
165 std::string type(match[1]);
166 if (type == "unified")
167 list.emplace(list.begin(), type, iter->path().string());
169 list.emplace_back(type, iter->path().string());
171 } catch (const std::exception& e) {
172 LOG(WARNING) << "Exception occurred: "
173 << typeid(e).name() << ", " << e.what();
181 void PkgRecoveryService::ProcessRecovery(uid_t uid,
182 const std::vector<RecoverEntry>& entries) {
183 LOG(INFO) << "Process recovery for user " << uid;
184 for (const auto& entry : entries) {
185 const char* type = entry.first.c_str();
186 const char* file = entry.second.c_str();
187 if (!fs::exists(file))
190 if (!RunBackend(uid, type, file))
191 LOG(ERROR) << "Recovery process for " << file << " failed";
199 PkgRecoveryService service;
203 LOG(ERROR) << "Exception occured";