blob: 3868ef230667d5bf3767e7bf7d11d4e9aab2cd2f [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
Tao Bao7ebef8f2018-12-14 15:22:40 -0800144 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)) {
Tao Bao49750f12018-07-11 16:32:10 -0700147 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
Tao Bao5ee25662018-07-11 15:55:32 -0700154bool CheckAndFreeSpaceOnCache(size_t bytes) {
Tianjie Xue40c80d2018-02-03 17:20:56 -0800155#ifndef __ANDROID__
Tao Baobd0fb232018-07-11 23:33:57 -0700156 // TODO(xunchang): Implement a heuristic cache size check during host simulation.
Tao Bao5ee25662018-07-11 15:55:32 -0700157 LOG(WARNING) << "Skipped making (" << bytes
Tao Baobd0fb232018-07-11 23:33:57 -0700158 << ") bytes free space on /cache; program is running on host";
Tao Bao5ee25662018-07-11 15:55:32 -0700159 return true;
Tianjie Xue40c80d2018-02-03 17:20:56 -0800160#endif
161
Tao Baobd0fb232018-07-11 23:33:57 -0700162 std::vector<std::string> dirs{ "/cache", Paths::Get().cache_log_directory() };
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700163 for (const auto& dirname : dirs) {
Tao Bao5ee25662018-07-11 15:55:32 -0700164 if (RemoveFilesInDirectory(bytes, dirname, FreeSpaceForFile)) {
165 return true;
Doug Zongker512536a2010-02-17 16:11:44 -0800166 }
167 }
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700168
Tao Bao5ee25662018-07-11 15:55:32 -0700169 return false;
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700170}
171
172bool RemoveFilesInDirectory(size_t bytes_needed, const std::string& dirname,
Tao Bao49750f12018-07-11 16:32:10 -0700173 const std::function<int64_t(const std::string&)>& space_checker) {
Tao Bao7ebef8f2018-12-14 15:22:40 -0800174 // 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
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700181 struct stat st;
Tao Baobd0fb232018-07-11 23:33:57 -0700182 if (stat(dirname.c_str(), &st) == -1) {
183 PLOG(ERROR) << "Failed to stat " << dirname;
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700184 return false;
185 }
186 if (!S_ISDIR(st.st_mode)) {
Tao Baobd0fb232018-07-11 23:33:57 -0700187 LOG(ERROR) << dirname << " is not a directory";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700188 return false;
189 }
190
Tao Bao49750f12018-07-11 16:32:10 -0700191 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 }
Tao Baobd0fb232018-07-11 23:33:57 -0700196 LOG(INFO) << free_now << " bytes free on " << dirname << " (" << bytes_needed << " needed)";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700197
Tao Bao7ebef8f2018-12-14 15:22:40 -0800198 if (free_now >= static_cast<int64_t>(bytes_needed)) {
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700199 return true;
200 }
201
202 std::vector<std::string> files;
Tao Bao641fa972018-04-25 18:59:40 -0700203 if (dirname == Paths::Get().cache_log_directory()) {
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700204 // 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) {
Tao Baobd0fb232018-07-11 23:33:57 -0700231 PLOG(ERROR) << "Failed to delete " << file;
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700232 continue;
233 }
234
235 free_now = space_checker(dirname);
Tao Bao49750f12018-07-11 16:32:10 -0700236 if (free_now == -1) {
237 LOG(ERROR) << "Failed to check free space for " << dirname;
238 return false;
239 }
Tao Baobd0fb232018-07-11 23:33:57 -0700240 LOG(INFO) << "Deleted " << file << "; now " << free_now << " bytes free";
Tao Bao7ebef8f2018-12-14 15:22:40 -0800241 if (free_now >= static_cast<int64_t>(bytes_needed)) {
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700242 return true;
243 }
244 }
245
246 return false;
Doug Zongker512536a2010-02-17 16:11:44 -0800247}