blob: 5a08a63ed1cbe5b0857b9dfd928d2994c9151cdd [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>
Doug Zongker512536a2010-02-17 16:11:44 -080019#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/stat.h>
Doug Zongker512536a2010-02-17 16:11:44 -080023#include <unistd.h>
Doug Zongker512536a2010-02-17 16:11:44 -080024
Tianjie Xud5fbcc12018-04-11 14:38:09 -070025#include <algorithm>
26#include <limits>
Yabin Cuid483c202016-02-03 17:08:52 -080027#include <memory>
28#include <set>
29#include <string>
30
Tianjie Xud5fbcc12018-04-11 14:38:09 -070031#include <android-base/file.h>
Tao Baobd0fb232018-07-11 23:33:57 -070032#include <android-base/logging.h>
Yabin Cuid483c202016-02-03 17:08:52 -080033#include <android-base/parseint.h>
34#include <android-base/stringprintf.h>
Tianjie Xud5fbcc12018-04-11 14:38:09 -070035#include <android-base/strings.h>
Yabin Cuid483c202016-02-03 17:08:52 -080036
Tao Baod80a9982016-03-03 11:43:47 -080037#include "applypatch/applypatch.h"
Tao Bao641fa972018-04-25 18:59:40 -070038#include "otautil/paths.h"
Doug Zongker512536a2010-02-17 16:11:44 -080039
Tianjie Xud5fbcc12018-04-11 14:38:09 -070040static int EliminateOpenFiles(const std::string& dirname, std::set<std::string>* files) {
Yabin Cuid483c202016-02-03 17:08:52 -080041 std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
42 if (!d) {
Tao Baobd0fb232018-07-11 23:33:57 -070043 PLOG(ERROR) << "Failed to open /proc";
Doug Zongker512536a2010-02-17 16:11:44 -080044 return -1;
45 }
Yabin Cuid483c202016-02-03 17:08:52 -080046 struct dirent* de;
47 while ((de = readdir(d.get())) != 0) {
48 unsigned int pid;
49 if (!android::base::ParseUint(de->d_name, &pid)) {
50 continue;
51 }
52 std::string path = android::base::StringPrintf("/proc/%s/fd/", de->d_name);
Doug Zongker512536a2010-02-17 16:11:44 -080053
Doug Zongker512536a2010-02-17 16:11:44 -080054 struct dirent* fdde;
Yabin Cuid483c202016-02-03 17:08:52 -080055 std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir);
56 if (!fdd) {
Tao Baobd0fb232018-07-11 23:33:57 -070057 PLOG(ERROR) << "Failed to open " << path;
Doug Zongker512536a2010-02-17 16:11:44 -080058 continue;
59 }
Yabin Cuid483c202016-02-03 17:08:52 -080060 while ((fdde = readdir(fdd.get())) != 0) {
61 std::string fd_path = path + fdde->d_name;
Doug Zongker512536a2010-02-17 16:11:44 -080062 char link[FILENAME_MAX];
Doug Zongker512536a2010-02-17 16:11:44 -080063
Yabin Cuid483c202016-02-03 17:08:52 -080064 int count = readlink(fd_path.c_str(), link, sizeof(link)-1);
Doug Zongker512536a2010-02-17 16:11:44 -080065 if (count >= 0) {
66 link[count] = '\0';
Tianjie Xud5fbcc12018-04-11 14:38:09 -070067 if (android::base::StartsWith(link, dirname)) {
Yabin Cuid483c202016-02-03 17:08:52 -080068 if (files->erase(link) > 0) {
Tao Baobd0fb232018-07-11 23:33:57 -070069 LOG(INFO) << link << " is open by " << de->d_name;
Doug Zongker512536a2010-02-17 16:11:44 -080070 }
71 }
72 }
73 }
Doug Zongker512536a2010-02-17 16:11:44 -080074 }
Doug Zongker512536a2010-02-17 16:11:44 -080075 return 0;
76}
77
Tianjie Xud5fbcc12018-04-11 14:38:09 -070078static std::vector<std::string> FindExpendableFiles(
79 const std::string& dirname, const std::function<bool(const std::string&)>& name_filter) {
Tianjie Xud5fbcc12018-04-11 14:38:09 -070080 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirname.c_str()), closedir);
81 if (!d) {
Tao Baobd0fb232018-07-11 23:33:57 -070082 PLOG(ERROR) << "Failed to open " << dirname;
Tianjie Xud5fbcc12018-04-11 14:38:09 -070083 return {};
84 }
85
86 // Look for regular files in the directory (not in any subdirectories).
Tao Baobd0fb232018-07-11 23:33:57 -070087 std::set<std::string> files;
Tianjie Xud5fbcc12018-04-11 14:38:09 -070088 struct dirent* de;
89 while ((de = readdir(d.get())) != 0) {
90 std::string path = dirname + "/" + de->d_name;
91
92 // We can't delete cache_temp_source; if it's there we might have restarted during
93 // installation and could be depending on it to be there.
Tao Bao641fa972018-04-25 18:59:40 -070094 if (path == Paths::Get().cache_temp_source()) {
Doug Zongker512536a2010-02-17 16:11:44 -080095 continue;
96 }
97
Tianjie Xud5fbcc12018-04-11 14:38:09 -070098 // Do not delete the file if it doesn't have the expected format.
99 if (name_filter != nullptr && !name_filter(de->d_name)) {
100 continue;
101 }
Doug Zongker512536a2010-02-17 16:11:44 -0800102
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700103 struct stat st;
104 if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
105 files.insert(path);
Doug Zongker512536a2010-02-17 16:11:44 -0800106 }
Doug Zongker512536a2010-02-17 16:11:44 -0800107 }
108
Tao Baobd0fb232018-07-11 23:33:57 -0700109 LOG(INFO) << files.size() << " regular files in deletable directory";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700110 if (EliminateOpenFiles(dirname, &files) < 0) {
111 return {};
Doug Zongker512536a2010-02-17 16:11:44 -0800112 }
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700113
114 return std::vector<std::string>(files.begin(), files.end());
115}
116
117// Parses the index of given log file, e.g. 3 for last_log.3; returns max number if the log name
118// doesn't have the expected format so that we'll delete these ones first.
119static unsigned int GetLogIndex(const std::string& log_name) {
120 if (log_name == "last_log" || log_name == "last_kmsg") {
121 return 0;
122 }
123
124 unsigned int index;
125 if (sscanf(log_name.c_str(), "last_log.%u", &index) == 1 ||
126 sscanf(log_name.c_str(), "last_kmsg.%u", &index) == 1) {
127 return index;
128 }
129
130 return std::numeric_limits<unsigned int>::max();
Doug Zongker512536a2010-02-17 16:11:44 -0800131}
132
133int MakeFreeSpaceOnCache(size_t bytes_needed) {
Tianjie Xue40c80d2018-02-03 17:20:56 -0800134#ifndef __ANDROID__
Tao Baobd0fb232018-07-11 23:33:57 -0700135 // TODO(xunchang): Implement a heuristic cache size check during host simulation.
136 LOG(WARNING) << "Skipped making (" << bytes_needed
137 << ") bytes free space on /cache; program is running on host";
Tianjie Xue40c80d2018-02-03 17:20:56 -0800138 return 0;
139#endif
140
Tao Baobd0fb232018-07-11 23:33:57 -0700141 std::vector<std::string> dirs{ "/cache", Paths::Get().cache_log_directory() };
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700142 for (const auto& dirname : dirs) {
143 if (RemoveFilesInDirectory(bytes_needed, dirname, FreeSpaceForFile)) {
144 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800145 }
146 }
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700147
148 return -1;
149}
150
151bool RemoveFilesInDirectory(size_t bytes_needed, const std::string& dirname,
152 const std::function<size_t(const std::string&)>& space_checker) {
153 struct stat st;
Tao Baobd0fb232018-07-11 23:33:57 -0700154 if (stat(dirname.c_str(), &st) == -1) {
155 PLOG(ERROR) << "Failed to stat " << dirname;
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700156 return false;
157 }
158 if (!S_ISDIR(st.st_mode)) {
Tao Baobd0fb232018-07-11 23:33:57 -0700159 LOG(ERROR) << dirname << " is not a directory";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700160 return false;
161 }
162
163 size_t free_now = space_checker(dirname);
Tao Baobd0fb232018-07-11 23:33:57 -0700164 LOG(INFO) << free_now << " bytes free on " << dirname << " (" << bytes_needed << " needed)";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700165
166 if (free_now >= bytes_needed) {
167 return true;
168 }
169
170 std::vector<std::string> files;
Tao Bao641fa972018-04-25 18:59:40 -0700171 if (dirname == Paths::Get().cache_log_directory()) {
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700172 // Deletes the log files only.
173 auto log_filter = [](const std::string& file_name) {
174 return android::base::StartsWith(file_name, "last_log") ||
175 android::base::StartsWith(file_name, "last_kmsg");
176 };
177
178 files = FindExpendableFiles(dirname, log_filter);
179
180 // Older logs will come to the top of the queue.
181 auto comparator = [](const std::string& name1, const std::string& name2) -> bool {
182 unsigned int index1 = GetLogIndex(android::base::Basename(name1));
183 unsigned int index2 = GetLogIndex(android::base::Basename(name2));
184 if (index1 == index2) {
185 return name1 < name2;
186 }
187
188 return index1 > index2;
189 };
190
191 std::sort(files.begin(), files.end(), comparator);
192 } else {
193 // We're allowed to delete unopened regular files in the directory.
194 files = FindExpendableFiles(dirname, nullptr);
195 }
196
197 for (const auto& file : files) {
198 if (unlink(file.c_str()) == -1) {
Tao Baobd0fb232018-07-11 23:33:57 -0700199 PLOG(ERROR) << "Failed to delete " << file;
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700200 continue;
201 }
202
203 free_now = space_checker(dirname);
Tao Baobd0fb232018-07-11 23:33:57 -0700204 LOG(INFO) << "Deleted " << file << "; now " << free_now << " bytes free";
Tianjie Xud5fbcc12018-04-11 14:38:09 -0700205 if (free_now >= bytes_needed) {
206 return true;
207 }
208 }
209
210 return false;
Doug Zongker512536a2010-02-17 16:11:44 -0800211}