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