• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 #include "host/commands/assemble_cvd/clean.h"
17 
18 #include <dirent.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21 
22 #include <regex>
23 #include <vector>
24 
25 #include <android-base/logging.h>
26 
27 #include "host/commands/assemble_cvd/flags.h"
28 #include "common/libs/utils/files.h"
29 
30 namespace cuttlefish {
31 namespace {
32 
CleanPriorFiles(const std::string & path,const std::set<std::string> & preserving)33 bool CleanPriorFiles(const std::string& path, const std::set<std::string>& preserving) {
34   if (preserving.count(cpp_basename(path))) {
35     LOG(DEBUG) << "Preserving: " << path;
36     return true;
37   }
38   struct stat statbuf;
39   if (lstat(path.c_str(), &statbuf) < 0) {
40     int error_num = errno;
41     if (error_num == ENOENT) {
42       return true;
43     } else {
44       LOG(ERROR) << "Could not stat \"" << path << "\": " << strerror(error_num);
45       return false;
46     }
47   }
48   if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
49     LOG(DEBUG) << "Deleting: " << path;
50     if (unlink(path.c_str()) < 0) {
51       int error_num = errno;
52       LOG(ERROR) << "Could not unlink \"" << path << "\", error was " << strerror(error_num);
53       return false;
54     }
55     return true;
56   }
57   std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(path.c_str()), closedir);
58   if (!dir) {
59     int error_num = errno;
60     LOG(ERROR) << "Could not clean \"" << path << "\": error was " << strerror(error_num);
61     return false;
62   }
63   for (auto entity = readdir(dir.get()); entity != nullptr; entity = readdir(dir.get())) {
64     std::string entity_name(entity->d_name);
65     if (entity_name == "." || entity_name == "..") {
66       continue;
67     }
68     std::string entity_path = path + "/" + entity_name;
69     if (!CleanPriorFiles(entity_path.c_str(), preserving)) {
70       return false;
71     }
72   }
73   if (rmdir(path.c_str()) < 0) {
74     if (!(errno == EEXIST || errno == ENOTEMPTY)) {
75       // If EEXIST or ENOTEMPTY, probably because a file was preserved
76       int error_num = errno;
77       LOG(ERROR) << "Could not rmdir \"" << path << "\", error was " << strerror(error_num);
78       return false;
79     }
80   }
81   return true;
82 }
83 
CleanPriorFiles(const std::vector<std::string> & paths,const std::set<std::string> & preserving)84 bool CleanPriorFiles(const std::vector<std::string>& paths, const std::set<std::string>& preserving) {
85   std::string prior_files;
86   for (auto path : paths) {
87     struct stat statbuf;
88     if (stat(path.c_str(), &statbuf) < 0 && errno != ENOENT) {
89       // If ENOENT, it doesn't exist yet, so there is no work to do'
90       int error_num = errno;
91       LOG(ERROR) << "Could not stat \"" << path << "\": " << strerror(error_num);
92       return false;
93     }
94     bool is_directory = (statbuf.st_mode & S_IFMT) == S_IFDIR;
95     prior_files += (is_directory ? (path + "/*") : path) + " ";
96   }
97   LOG(DEBUG) << "Assuming prior files of " << prior_files;
98   std::string lsof_cmd = "lsof -t " + prior_files + " >/dev/null 2>&1";
99   int rval = std::system(lsof_cmd.c_str());
100   // lsof returns 0 if any of the files are open
101   if (WEXITSTATUS(rval) == 0) {
102     LOG(ERROR) << "Clean aborted: files are in use";
103     return false;
104   }
105   for (const auto& path : paths) {
106     if (!CleanPriorFiles(path, preserving)) {
107       LOG(ERROR) << "Remove of file under \"" << path << "\" failed";
108       return false;
109     }
110   }
111   return true;
112 }
113 
114 } // namespace
115 
CleanPriorFiles(const std::set<std::string> & preserving,const std::string & assembly_dir,const std::string & instance_dir)116 bool CleanPriorFiles(
117     const std::set<std::string>& preserving,
118     const std::string& assembly_dir,
119     const std::string& instance_dir) {
120   std::vector<std::string> paths = {
121     // Everything in the assembly directory
122     assembly_dir,
123     // The environment file
124     GetCuttlefishEnvPath(),
125     // The global link to the config file
126     GetGlobalConfigFileLink(),
127   };
128 
129   std::string runtime_dir_parent = cpp_dirname(AbsolutePath(instance_dir));
130   std::string runtime_dirs_basename = cpp_basename(AbsolutePath(instance_dir));
131 
132   std::regex instance_dir_regex("^.+\\.[1-9]\\d*$");
133   for (const auto& path : DirectoryContents(runtime_dir_parent)) {
134     std::string absl_path = runtime_dir_parent + "/" + path;
135     if((path.rfind(runtime_dirs_basename, 0) == 0) && std::regex_match(path, instance_dir_regex) &&
136         DirectoryExists(absl_path)) {
137       paths.push_back(absl_path);
138     }
139   }
140   paths.push_back(instance_dir);
141   return CleanPriorFiles(paths, preserving);
142 }
143 
EnsureDirectoryExists(const std::string & directory_path)144 bool EnsureDirectoryExists(const std::string& directory_path) {
145   if (!DirectoryExists(directory_path)) {
146     LOG(DEBUG) << "Setting up " << directory_path;
147     if (mkdir(directory_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
148         && errno != EEXIST) {
149       PLOG(ERROR) << "Failed to create dir: \"" << directory_path << "\" ";
150       return false;
151     }
152   }
153   return true;
154 }
155 
156 } // namespace cuttlefish
157