1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #include <dirent.h>
18 #include <errno.h>
19 #include <inttypes.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <sys/statfs.h>
25 #include <unistd.h>
26
27 #include <algorithm>
28 #include <limits>
29 #include <memory>
30 #include <set>
31 #include <string>
32
33 #include <android-base/file.h>
34 #include <android-base/logging.h>
35 #include <android-base/parseint.h>
36 #include <android-base/stringprintf.h>
37 #include <android-base/strings.h>
38
39 #include "applypatch/applypatch.h"
40 #include "otautil/paths.h"
41
EliminateOpenFiles(const std::string & dirname,std::set<std::string> * files)42 static int EliminateOpenFiles(const std::string& dirname, std::set<std::string>* files) {
43 std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
44 if (!d) {
45 PLOG(ERROR) << "Failed to open /proc";
46 return -1;
47 }
48 struct dirent* de;
49 while ((de = readdir(d.get())) != 0) {
50 unsigned int pid;
51 if (!android::base::ParseUint(de->d_name, &pid)) {
52 continue;
53 }
54 std::string path = android::base::StringPrintf("/proc/%s/fd/", de->d_name);
55
56 struct dirent* fdde;
57 std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir);
58 if (!fdd) {
59 PLOG(ERROR) << "Failed to open " << path;
60 continue;
61 }
62 while ((fdde = readdir(fdd.get())) != 0) {
63 std::string fd_path = path + fdde->d_name;
64 char link[FILENAME_MAX];
65
66 int count = readlink(fd_path.c_str(), link, sizeof(link)-1);
67 if (count >= 0) {
68 link[count] = '\0';
69 if (android::base::StartsWith(link, dirname)) {
70 if (files->erase(link) > 0) {
71 LOG(INFO) << link << " is open by " << de->d_name;
72 }
73 }
74 }
75 }
76 }
77 return 0;
78 }
79
FindExpendableFiles(const std::string & dirname,const std::function<bool (const std::string &)> & name_filter)80 static std::vector<std::string> FindExpendableFiles(
81 const std::string& dirname, const std::function<bool(const std::string&)>& name_filter) {
82 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirname.c_str()), closedir);
83 if (!d) {
84 PLOG(ERROR) << "Failed to open " << dirname;
85 return {};
86 }
87
88 // Look for regular files in the directory (not in any subdirectories).
89 std::set<std::string> files;
90 struct dirent* de;
91 while ((de = readdir(d.get())) != 0) {
92 std::string path = dirname + "/" + de->d_name;
93
94 // We can't delete cache_temp_source; if it's there we might have restarted during
95 // installation and could be depending on it to be there.
96 if (path == Paths::Get().cache_temp_source()) {
97 continue;
98 }
99
100 // Do not delete the file if it doesn't have the expected format.
101 if (name_filter != nullptr && !name_filter(de->d_name)) {
102 continue;
103 }
104
105 struct stat st;
106 if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
107 files.insert(path);
108 }
109 }
110
111 LOG(INFO) << files.size() << " regular files in deletable directory";
112 if (EliminateOpenFiles(dirname, &files) < 0) {
113 return {};
114 }
115
116 return std::vector<std::string>(files.begin(), files.end());
117 }
118
119 // Parses the index of given log file, e.g. 3 for last_log.3; returns max number if the log name
120 // doesn't have the expected format so that we'll delete these ones first.
GetLogIndex(const std::string & log_name)121 static unsigned int GetLogIndex(const std::string& log_name) {
122 if (log_name == "last_log" || log_name == "last_kmsg") {
123 return 0;
124 }
125
126 unsigned int index;
127 if (sscanf(log_name.c_str(), "last_log.%u", &index) == 1 ||
128 sscanf(log_name.c_str(), "last_kmsg.%u", &index) == 1) {
129 return index;
130 }
131
132 return std::numeric_limits<unsigned int>::max();
133 }
134
135 // Returns the amount of free space (in bytes) on the filesystem containing filename, or -1 on
136 // error.
FreeSpaceForFile(const std::string & filename)137 static int64_t FreeSpaceForFile(const std::string& filename) {
138 struct statfs sf;
139 if (statfs(filename.c_str(), &sf) == -1) {
140 PLOG(ERROR) << "Failed to statfs " << filename;
141 return -1;
142 }
143
144 auto f_bsize = static_cast<int64_t>(sf.f_bsize);
145 auto free_space = sf.f_bsize * sf.f_bavail;
146 if (f_bsize == 0 || free_space / f_bsize != static_cast<int64_t>(sf.f_bavail)) {
147 LOG(ERROR) << "Invalid block size or overflow (sf.f_bsize " << sf.f_bsize << ", sf.f_bavail "
148 << sf.f_bavail << ")";
149 return -1;
150 }
151 return free_space;
152 }
153
CheckAndFreeSpaceOnCache(size_t bytes)154 bool CheckAndFreeSpaceOnCache(size_t bytes) {
155 #ifndef __ANDROID__
156 // TODO(xunchang): Implement a heuristic cache size check during host simulation.
157 LOG(WARNING) << "Skipped making (" << bytes
158 << ") bytes free space on /cache; program is running on host";
159 return true;
160 #endif
161
162 std::vector<std::string> dirs{ "/cache", Paths::Get().cache_log_directory() };
163 for (const auto& dirname : dirs) {
164 if (RemoveFilesInDirectory(bytes, dirname, FreeSpaceForFile)) {
165 return true;
166 }
167 }
168
169 return false;
170 }
171
RemoveFilesInDirectory(size_t bytes_needed,const std::string & dirname,const std::function<int64_t (const std::string &)> & space_checker)172 bool RemoveFilesInDirectory(size_t bytes_needed, const std::string& dirname,
173 const std::function<int64_t(const std::string&)>& space_checker) {
174 // The requested size cannot exceed max int64_t.
175 if (static_cast<uint64_t>(bytes_needed) >
176 static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
177 LOG(ERROR) << "Invalid arg of bytes_needed: " << bytes_needed;
178 return false;
179 }
180
181 struct stat st;
182 if (stat(dirname.c_str(), &st) == -1) {
183 PLOG(ERROR) << "Failed to stat " << dirname;
184 return false;
185 }
186 if (!S_ISDIR(st.st_mode)) {
187 LOG(ERROR) << dirname << " is not a directory";
188 return false;
189 }
190
191 int64_t free_now = space_checker(dirname);
192 if (free_now == -1) {
193 LOG(ERROR) << "Failed to check free space for " << dirname;
194 return false;
195 }
196 LOG(INFO) << free_now << " bytes free on " << dirname << " (" << bytes_needed << " needed)";
197
198 if (free_now >= static_cast<int64_t>(bytes_needed)) {
199 return true;
200 }
201
202 std::vector<std::string> files;
203 if (dirname == Paths::Get().cache_log_directory()) {
204 // Deletes the log files only.
205 auto log_filter = [](const std::string& file_name) {
206 return android::base::StartsWith(file_name, "last_log") ||
207 android::base::StartsWith(file_name, "last_kmsg");
208 };
209
210 files = FindExpendableFiles(dirname, log_filter);
211
212 // Older logs will come to the top of the queue.
213 auto comparator = [](const std::string& name1, const std::string& name2) -> bool {
214 unsigned int index1 = GetLogIndex(android::base::Basename(name1));
215 unsigned int index2 = GetLogIndex(android::base::Basename(name2));
216 if (index1 == index2) {
217 return name1 < name2;
218 }
219
220 return index1 > index2;
221 };
222
223 std::sort(files.begin(), files.end(), comparator);
224 } else {
225 // We're allowed to delete unopened regular files in the directory.
226 files = FindExpendableFiles(dirname, nullptr);
227 }
228
229 for (const auto& file : files) {
230 if (unlink(file.c_str()) == -1) {
231 PLOG(ERROR) << "Failed to delete " << file;
232 continue;
233 }
234
235 free_now = space_checker(dirname);
236 if (free_now == -1) {
237 LOG(ERROR) << "Failed to check free space for " << dirname;
238 return false;
239 }
240 LOG(INFO) << "Deleted " << file << "; now " << free_now << " bytes free";
241 if (free_now >= static_cast<int64_t>(bytes_needed)) {
242 return true;
243 }
244 }
245
246 return false;
247 }
248