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 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 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. 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. 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 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 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