blob: e4878655e7b62b9ce2e555dc5b4e81d6f06bec67 [file] [log] [blame]
Tao Baoba9a42a2015-06-23 23:23:33 -07001/*
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
Tianjie Xud5fbcc12018-04-11 14:38:09 -070017#include <dirent.h>
Doug Zongker512536a2010-02-17 16:11:44 -080018#include <errno.h>
Tao Bao49750f12018-07-11 16:32:10 -070019#include <inttypes.h>
Doug Zongker512536a2010-02-17 16:11:44 -080020#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/stat.h>
Tao Bao49750f12018-07-11 16:32:10 -070024#include <sys/statfs.h>
Doug Zongker512536a2010-02-17 16:11:44 -080025#include <unistd.h>
Doug Zongker512536a2010-02-17 16:11:44 -080026
Tianjie Xud5fbcc12018-04-11 14:38:09 -070027#include <algorithm>
28#include <limits>
Yabin Cuid483c202016-02-03 17:08:52 -080029#include <memory>
30#include <set>
31#include <string>
32
Tianjie Xud5fbcc12018-04-11 14:38:09 -070033#include <android-base/file.h>
Tao Baobd0fb232018-07-11 23:33:57 -070034#include <android-base/logging.h>
Yabin Cuid483c202016-02-03 17:08:52 -080035#include <android-base/parseint.h>
36#include <android-base/stringprintf.h>
Tianjie Xud5fbcc12018-04-11 14:38:09 -070037#include <android-base/strings.h>
Yabin Cuid483c202016-02-03 17:08:52 -080038
Tao Baod80a9982016-03-03 11:43:47 -080039#include "applypatch/applypatch.h"
Tao Bao641fa972018-04-25 18:59:40 -070040#include "otautil/paths.h"
Doug Zongker512536a2010-02-17 16:11:44 -080041
Tianjie Xud5fbcc12018-04-11 14:38:09 -070042static int EliminateOpenFiles(const std::string& dirname, std::set<std::string>* files) {
Yabin Cuid483c202016-02-03 17:08:52 -080043 std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
44 if (!d) {
Tao Baobd0fb232018-07-11 23:33:57 -070045 PLOG(ERROR) << "Failed to open /proc";
Doug Zongker512536a2010-02-17 16:11:44 -080046 return -1;
47 }
Yabin Cuid483c202016-02-03 17:08:52 -080048 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);
Doug Zongker512536a2010-02-17 16:11:44 -080055
Doug Zongker512536a2010-02-17 16:11:44 -080056 struct dirent* fdde;
Yabin Cuid483c202016-02-03 17:08:52 -080057 std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir);
58 if (!fdd) {
Tao Baobd0fb232018-07-11 23:33:57 -070059 PLOG(ERROR) << "Failed to open " << path;
Doug Zongker512536a2010-02-17 16:11:44 -080060 continue;
61 }
Yabin Cuid483c202016-02-03 17:08:52 -080062 while ((fdde = readdir(fdd.get())) != 0) {
63 std::string fd_path = path + fdde->d_name;
Doug Zongker512536a2010-02-17 16:11:44 -080064 char link[FILENAME_MAX];
Doug Zongker512536a2010-02-17 16:11:44 -080065
Yabin Cuid483c202016-02-03 17:08:52 -080066 int count = readlink(fd_path.c_str(), link, sizeof(link)-1);
Doug Zongker512536a2010-02-17 16:11:44 -080067 if (count >= 0) {
68 link[count] = '\0';
Tianjie Xud5fbcc12018-04-11 14:38:09 -070069 if (android::base::StartsWith(link, dirname)) {
Yabin Cuid483c202016-02-03 17:08:52 -080070 if (files->erase(link) > 0) {
Tao Baobd0fb232018-07-11 23:33:57 -070071 LOG(INFO) << link << " is open by " << de->d_name;
Doug Zongker512536a2010-02-17 16:11:44 -080072 }
73 }
74 }
75 }
Doug Zongker512536a2010-02-17 16:11:44 -080076 }
Doug Zongker512536a2010-02-17 16:11:44 -080077 return 0;
78}
79
Tianjie Xud5fbcc12018-04-11 14:38:09 -070080static std::vector<std::string> FindExpendableFiles(
81 const std::string& dirname, const std::function<bool(const std::string&)>& name_filter) {
Tianjie Xud5fbcc12018-04-11 14:38:09 -070082 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirname.c_str()), closedir);
83 if (!d) {
Tao Baobd0fb232018-07-11 23:33:57 -070084 PLOG(ERROR) << "Failed to open " << dirname;
Tianjie Xud5fbcc12018-04-11 14:38:09 -070085 return {};
86 }
87
88 // Look for regular files in the directory (not in any subdirectories).
Tao Baobd0fb232018-07-11 23:33:57 -070089 std::set<std::string> files;
Tianjie Xud5fbcc12018-04-11 14:38:09 -070090 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.
Tao Bao641fa972018-04-25 18:59:40 -070096 if (path == Paths::Get().cache_temp_source()) {
Doug Zongker512536a2010-02-17 16:11:44 -080097 continue;
98 }
99
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700100 // 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 }
Doug Zongker512536a2010-02-17 16:11:44 -0800104
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700105 struct stat st;
106 if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
107 files.insert(path);
Doug Zongker512536a2010-02-17 16:11:44 -0800108 }
Doug Zongker512536a2010-02-17 16:11:44 -0800109 }
110
Tao Baobd0fb232018-07-11 23:33:57 -0700111 LOG(INFO) << files.size() << " regular files in deletable directory";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700112 if (EliminateOpenFiles(dirname, &files) < 0) {
113 return {};
Doug Zongker512536a2010-02-17 16:11:44 -0800114 }
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700115
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.
121static 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();
Doug Zongker512536a2010-02-17 16:11:44 -0800133}
134
Tao Bao49750f12018-07-11 16:32:10 -0700135// Returns the amount of free space (in bytes) on the filesystem containing filename, or -1 on
136// error.
137static 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 int64_t free_space = static_cast<int64_t>(sf.f_bsize) * sf.f_bavail;
145 if (sf.f_bsize == 0 || free_space / sf.f_bsize != sf.f_bavail) {
146 LOG(ERROR) << "Invalid block size or overflow (sf.f_bsize " << sf.f_bsize << ", sf.f_bavail "
147 << sf.f_bavail << ")";
148 return -1;
149 }
150 return free_space;
151}
152
Tao Bao5ee25662018-07-11 15:55:32 -0700153bool CheckAndFreeSpaceOnCache(size_t bytes) {
Tianjie Xue40c80d2018-02-03 17:20:56 -0800154#ifndef __ANDROID__
Tao Baobd0fb232018-07-11 23:33:57 -0700155 // TODO(xunchang): Implement a heuristic cache size check during host simulation.
Tao Bao5ee25662018-07-11 15:55:32 -0700156 LOG(WARNING) << "Skipped making (" << bytes
Tao Baobd0fb232018-07-11 23:33:57 -0700157 << ") bytes free space on /cache; program is running on host";
Tao Bao5ee25662018-07-11 15:55:32 -0700158 return true;
Tianjie Xue40c80d2018-02-03 17:20:56 -0800159#endif
160
Tao Baobd0fb232018-07-11 23:33:57 -0700161 std::vector<std::string> dirs{ "/cache", Paths::Get().cache_log_directory() };
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700162 for (const auto& dirname : dirs) {
Tao Bao5ee25662018-07-11 15:55:32 -0700163 if (RemoveFilesInDirectory(bytes, dirname, FreeSpaceForFile)) {
164 return true;
Doug Zongker512536a2010-02-17 16:11:44 -0800165 }
166 }
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700167
Tao Bao5ee25662018-07-11 15:55:32 -0700168 return false;
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700169}
170
171bool RemoveFilesInDirectory(size_t bytes_needed, const std::string& dirname,
Tao Bao49750f12018-07-11 16:32:10 -0700172 const std::function<int64_t(const std::string&)>& space_checker) {
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700173 struct stat st;
Tao Baobd0fb232018-07-11 23:33:57 -0700174 if (stat(dirname.c_str(), &st) == -1) {
175 PLOG(ERROR) << "Failed to stat " << dirname;
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700176 return false;
177 }
178 if (!S_ISDIR(st.st_mode)) {
Tao Baobd0fb232018-07-11 23:33:57 -0700179 LOG(ERROR) << dirname << " is not a directory";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700180 return false;
181 }
182
Tao Bao49750f12018-07-11 16:32:10 -0700183 int64_t free_now = space_checker(dirname);
184 if (free_now == -1) {
185 LOG(ERROR) << "Failed to check free space for " << dirname;
186 return false;
187 }
Tao Baobd0fb232018-07-11 23:33:57 -0700188 LOG(INFO) << free_now << " bytes free on " << dirname << " (" << bytes_needed << " needed)";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700189
190 if (free_now >= bytes_needed) {
191 return true;
192 }
193
194 std::vector<std::string> files;
Tao Bao641fa972018-04-25 18:59:40 -0700195 if (dirname == Paths::Get().cache_log_directory()) {
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700196 // Deletes the log files only.
197 auto log_filter = [](const std::string& file_name) {
198 return android::base::StartsWith(file_name, "last_log") ||
199 android::base::StartsWith(file_name, "last_kmsg");
200 };
201
202 files = FindExpendableFiles(dirname, log_filter);
203
204 // Older logs will come to the top of the queue.
205 auto comparator = [](const std::string& name1, const std::string& name2) -> bool {
206 unsigned int index1 = GetLogIndex(android::base::Basename(name1));
207 unsigned int index2 = GetLogIndex(android::base::Basename(name2));
208 if (index1 == index2) {
209 return name1 < name2;
210 }
211
212 return index1 > index2;
213 };
214
215 std::sort(files.begin(), files.end(), comparator);
216 } else {
217 // We're allowed to delete unopened regular files in the directory.
218 files = FindExpendableFiles(dirname, nullptr);
219 }
220
221 for (const auto& file : files) {
222 if (unlink(file.c_str()) == -1) {
Tao Baobd0fb232018-07-11 23:33:57 -0700223 PLOG(ERROR) << "Failed to delete " << file;
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700224 continue;
225 }
226
227 free_now = space_checker(dirname);
Tao Bao49750f12018-07-11 16:32:10 -0700228 if (free_now == -1) {
229 LOG(ERROR) << "Failed to check free space for " << dirname;
230 return false;
231 }
Tao Baobd0fb232018-07-11 23:33:57 -0700232 LOG(INFO) << "Deleted " << file << "; now " << free_now << " bytes free";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700233 if (free_now >= bytes_needed) {
234 return true;
235 }
236 }
237
238 return false;
Doug Zongker512536a2010-02-17 16:11:44 -0800239}