xref: /aosp_15_r20/system/incremental_delivery/incfs/MountRegistry.cpp (revision 9190c2a8bd3622b7aa9bd7bfe4b3aec77820f478)
1*9190c2a8SAndroid Build Coastguard Worker /*
2*9190c2a8SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*9190c2a8SAndroid Build Coastguard Worker  *
4*9190c2a8SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*9190c2a8SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*9190c2a8SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*9190c2a8SAndroid Build Coastguard Worker  *
8*9190c2a8SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*9190c2a8SAndroid Build Coastguard Worker  *
10*9190c2a8SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*9190c2a8SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*9190c2a8SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9190c2a8SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*9190c2a8SAndroid Build Coastguard Worker  * limitations under the License.
15*9190c2a8SAndroid Build Coastguard Worker  */
16*9190c2a8SAndroid Build Coastguard Worker 
17*9190c2a8SAndroid Build Coastguard Worker #define LOG_TAG "incfs-mounts"
18*9190c2a8SAndroid Build Coastguard Worker 
19*9190c2a8SAndroid Build Coastguard Worker #include "MountRegistry.h"
20*9190c2a8SAndroid Build Coastguard Worker 
21*9190c2a8SAndroid Build Coastguard Worker #include <android-base/logging.h>
22*9190c2a8SAndroid Build Coastguard Worker #include <poll.h>
23*9190c2a8SAndroid Build Coastguard Worker #include <stdlib.h>
24*9190c2a8SAndroid Build Coastguard Worker 
25*9190c2a8SAndroid Build Coastguard Worker #include <charconv>
26*9190c2a8SAndroid Build Coastguard Worker #include <set>
27*9190c2a8SAndroid Build Coastguard Worker #include <unordered_map>
28*9190c2a8SAndroid Build Coastguard Worker 
29*9190c2a8SAndroid Build Coastguard Worker #include "incfs.h"
30*9190c2a8SAndroid Build Coastguard Worker #include "path.h"
31*9190c2a8SAndroid Build Coastguard Worker #include "split.h"
32*9190c2a8SAndroid Build Coastguard Worker 
33*9190c2a8SAndroid Build Coastguard Worker using namespace std::literals;
34*9190c2a8SAndroid Build Coastguard Worker 
35*9190c2a8SAndroid Build Coastguard Worker namespace android::incfs {
36*9190c2a8SAndroid Build Coastguard Worker 
37*9190c2a8SAndroid Build Coastguard Worker // /proc/self/mountinfo may have some special characters in paths replaced with their
38*9190c2a8SAndroid Build Coastguard Worker // octal codes in the following pattern: '\xxx', e.g. \040 for space character.
39*9190c2a8SAndroid Build Coastguard Worker // This function translates those patterns back into corresponding characters.
fixProcPath(std::string & path)40*9190c2a8SAndroid Build Coastguard Worker static void fixProcPath(std::string& path) {
41*9190c2a8SAndroid Build Coastguard Worker     static const auto kPrefix = "\\"sv;
42*9190c2a8SAndroid Build Coastguard Worker     static const auto kPatternLength = 4;
43*9190c2a8SAndroid Build Coastguard Worker     auto pos = std::search(path.begin(), path.end(), kPrefix.begin(), kPrefix.end());
44*9190c2a8SAndroid Build Coastguard Worker     if (pos == path.end()) {
45*9190c2a8SAndroid Build Coastguard Worker         return;
46*9190c2a8SAndroid Build Coastguard Worker     }
47*9190c2a8SAndroid Build Coastguard Worker     auto dest = pos;
48*9190c2a8SAndroid Build Coastguard Worker     do {
49*9190c2a8SAndroid Build Coastguard Worker         if (path.end() - pos < kPatternLength || !std::equal(kPrefix.begin(), kPrefix.end(), pos)) {
50*9190c2a8SAndroid Build Coastguard Worker             *dest++ = *pos++;
51*9190c2a8SAndroid Build Coastguard Worker         } else {
52*9190c2a8SAndroid Build Coastguard Worker             int charCode;
53*9190c2a8SAndroid Build Coastguard Worker             auto res = std::from_chars(&*(pos + kPrefix.size()), &*(pos + kPatternLength), charCode,
54*9190c2a8SAndroid Build Coastguard Worker                                        8);
55*9190c2a8SAndroid Build Coastguard Worker             if (res.ec == std::errc{}) {
56*9190c2a8SAndroid Build Coastguard Worker                 *dest++ = char(charCode);
57*9190c2a8SAndroid Build Coastguard Worker             } else {
58*9190c2a8SAndroid Build Coastguard Worker                 // Didn't convert, let's keep it as is.
59*9190c2a8SAndroid Build Coastguard Worker                 dest = std::copy(pos, pos + kPatternLength, dest);
60*9190c2a8SAndroid Build Coastguard Worker                 pos += kPatternLength;
61*9190c2a8SAndroid Build Coastguard Worker             }
62*9190c2a8SAndroid Build Coastguard Worker         }
63*9190c2a8SAndroid Build Coastguard Worker     } while (pos != path.end());
64*9190c2a8SAndroid Build Coastguard Worker     path.erase(dest, path.end());
65*9190c2a8SAndroid Build Coastguard Worker }
66*9190c2a8SAndroid Build Coastguard Worker 
binds() const67*9190c2a8SAndroid Build Coastguard Worker std::vector<std::pair<std::string_view, std::string_view>> MountRegistry::Mounts::Mount::binds()
68*9190c2a8SAndroid Build Coastguard Worker         const {
69*9190c2a8SAndroid Build Coastguard Worker     std::vector<std::pair<std::string_view, std::string_view>> result;
70*9190c2a8SAndroid Build Coastguard Worker     result.reserve(mBase->binds.size());
71*9190c2a8SAndroid Build Coastguard Worker     for (auto it : mBase->binds) {
72*9190c2a8SAndroid Build Coastguard Worker         result.emplace_back(it->second.subdir, it->first);
73*9190c2a8SAndroid Build Coastguard Worker     }
74*9190c2a8SAndroid Build Coastguard Worker     return result;
75*9190c2a8SAndroid Build Coastguard Worker }
76*9190c2a8SAndroid Build Coastguard Worker 
swap(MountRegistry::Mounts & other)77*9190c2a8SAndroid Build Coastguard Worker void MountRegistry::Mounts::swap(MountRegistry::Mounts& other) {
78*9190c2a8SAndroid Build Coastguard Worker     roots.swap(other.roots);
79*9190c2a8SAndroid Build Coastguard Worker     rootByBindPoint.swap(other.rootByBindPoint);
80*9190c2a8SAndroid Build Coastguard Worker }
81*9190c2a8SAndroid Build Coastguard Worker 
clear()82*9190c2a8SAndroid Build Coastguard Worker void MountRegistry::Mounts::clear() {
83*9190c2a8SAndroid Build Coastguard Worker     roots.clear();
84*9190c2a8SAndroid Build Coastguard Worker     rootByBindPoint.clear();
85*9190c2a8SAndroid Build Coastguard Worker }
86*9190c2a8SAndroid Build Coastguard Worker 
rootIndex(std::string_view path) const87*9190c2a8SAndroid Build Coastguard Worker std::pair<int, MountRegistry::BindMap::const_iterator> MountRegistry::Mounts::rootIndex(
88*9190c2a8SAndroid Build Coastguard Worker         std::string_view path) const {
89*9190c2a8SAndroid Build Coastguard Worker     auto it = rootByBindPoint.lower_bound(path);
90*9190c2a8SAndroid Build Coastguard Worker     if (it != rootByBindPoint.end() && it->first == path) {
91*9190c2a8SAndroid Build Coastguard Worker         return {it->second.rootIndex, it};
92*9190c2a8SAndroid Build Coastguard Worker     }
93*9190c2a8SAndroid Build Coastguard Worker     if (it != rootByBindPoint.begin()) {
94*9190c2a8SAndroid Build Coastguard Worker         --it;
95*9190c2a8SAndroid Build Coastguard Worker         if (path::startsWith(path, it->first) && path.size() > it->first.size()) {
96*9190c2a8SAndroid Build Coastguard Worker             const auto index = it->second.rootIndex;
97*9190c2a8SAndroid Build Coastguard Worker             if (index >= int(roots.size()) || roots[index].empty()) {
98*9190c2a8SAndroid Build Coastguard Worker                 LOG(ERROR) << "[incfs] Root for path '" << path << "' #" << index
99*9190c2a8SAndroid Build Coastguard Worker                            << " is not valid";
100*9190c2a8SAndroid Build Coastguard Worker                 return {-1, {}};
101*9190c2a8SAndroid Build Coastguard Worker             }
102*9190c2a8SAndroid Build Coastguard Worker             return {index, it};
103*9190c2a8SAndroid Build Coastguard Worker         }
104*9190c2a8SAndroid Build Coastguard Worker     }
105*9190c2a8SAndroid Build Coastguard Worker     return {-1, {}};
106*9190c2a8SAndroid Build Coastguard Worker }
107*9190c2a8SAndroid Build Coastguard Worker 
rootFor(std::string_view path) const108*9190c2a8SAndroid Build Coastguard Worker std::string_view MountRegistry::Mounts::rootFor(std::string_view path) const {
109*9190c2a8SAndroid Build Coastguard Worker     auto [index, _] = rootIndex(path::normalize(path));
110*9190c2a8SAndroid Build Coastguard Worker     if (index < 0) {
111*9190c2a8SAndroid Build Coastguard Worker         return {};
112*9190c2a8SAndroid Build Coastguard Worker     }
113*9190c2a8SAndroid Build Coastguard Worker     return roots[index].path;
114*9190c2a8SAndroid Build Coastguard Worker }
115*9190c2a8SAndroid Build Coastguard Worker 
rootAndSubpathFor(std::string_view path) const116*9190c2a8SAndroid Build Coastguard Worker auto MountRegistry::Mounts::rootAndSubpathFor(std::string_view path) const
117*9190c2a8SAndroid Build Coastguard Worker         -> std::pair<const Root*, std::string> {
118*9190c2a8SAndroid Build Coastguard Worker     auto normalPath = path::normalize(path);
119*9190c2a8SAndroid Build Coastguard Worker     auto [index, bindIt] = rootIndex(normalPath);
120*9190c2a8SAndroid Build Coastguard Worker     if (index < 0) {
121*9190c2a8SAndroid Build Coastguard Worker         return {};
122*9190c2a8SAndroid Build Coastguard Worker     }
123*9190c2a8SAndroid Build Coastguard Worker 
124*9190c2a8SAndroid Build Coastguard Worker     const auto& bindSubdir = bindIt->second.subdir;
125*9190c2a8SAndroid Build Coastguard Worker     const auto pastBindSubdir = path::relativize(bindIt->first, normalPath);
126*9190c2a8SAndroid Build Coastguard Worker     const auto& root = roots[index];
127*9190c2a8SAndroid Build Coastguard Worker     return {&root, path::join(bindSubdir, pastBindSubdir)};
128*9190c2a8SAndroid Build Coastguard Worker }
129*9190c2a8SAndroid Build Coastguard Worker 
addRoot(std::string_view root,std::string_view backingDir)130*9190c2a8SAndroid Build Coastguard Worker void MountRegistry::Mounts::addRoot(std::string_view root, std::string_view backingDir) {
131*9190c2a8SAndroid Build Coastguard Worker     const auto index = roots.size();
132*9190c2a8SAndroid Build Coastguard Worker     auto absolute = path::normalize(root);
133*9190c2a8SAndroid Build Coastguard Worker     auto it = rootByBindPoint.insert_or_assign(absolute, Bind{std::string(), int(index)}).first;
134*9190c2a8SAndroid Build Coastguard Worker     roots.push_back({std::move(absolute), path::normalize(backingDir), {it}});
135*9190c2a8SAndroid Build Coastguard Worker }
136*9190c2a8SAndroid Build Coastguard Worker 
removeRoot(std::string_view root)137*9190c2a8SAndroid Build Coastguard Worker void MountRegistry::Mounts::removeRoot(std::string_view root) {
138*9190c2a8SAndroid Build Coastguard Worker     auto absolute = path::normalize(root);
139*9190c2a8SAndroid Build Coastguard Worker     auto it = rootByBindPoint.find(absolute);
140*9190c2a8SAndroid Build Coastguard Worker     if (it == rootByBindPoint.end()) {
141*9190c2a8SAndroid Build Coastguard Worker         LOG(WARNING) << "[incfs] Trying to remove non-existent root '" << root << '\'';
142*9190c2a8SAndroid Build Coastguard Worker         return;
143*9190c2a8SAndroid Build Coastguard Worker     }
144*9190c2a8SAndroid Build Coastguard Worker     const auto index = it->second.rootIndex;
145*9190c2a8SAndroid Build Coastguard Worker     if (index >= int(roots.size())) {
146*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << "[incfs] Root '" << root << "' has index " << index
147*9190c2a8SAndroid Build Coastguard Worker                    << " out of bounds (total roots count is " << roots.size();
148*9190c2a8SAndroid Build Coastguard Worker         return;
149*9190c2a8SAndroid Build Coastguard Worker     }
150*9190c2a8SAndroid Build Coastguard Worker 
151*9190c2a8SAndroid Build Coastguard Worker     for (auto bindIt : roots[index].binds) {
152*9190c2a8SAndroid Build Coastguard Worker         rootByBindPoint.erase(bindIt);
153*9190c2a8SAndroid Build Coastguard Worker     }
154*9190c2a8SAndroid Build Coastguard Worker 
155*9190c2a8SAndroid Build Coastguard Worker     if (index + 1 == int(roots.size())) {
156*9190c2a8SAndroid Build Coastguard Worker         roots.pop_back();
157*9190c2a8SAndroid Build Coastguard Worker         // Run a small GC job here as we may be able to remove some obsolete
158*9190c2a8SAndroid Build Coastguard Worker         // entries.
159*9190c2a8SAndroid Build Coastguard Worker         while (roots.back().empty()) {
160*9190c2a8SAndroid Build Coastguard Worker             roots.pop_back();
161*9190c2a8SAndroid Build Coastguard Worker         }
162*9190c2a8SAndroid Build Coastguard Worker     } else {
163*9190c2a8SAndroid Build Coastguard Worker         roots[index].clear();
164*9190c2a8SAndroid Build Coastguard Worker     }
165*9190c2a8SAndroid Build Coastguard Worker }
166*9190c2a8SAndroid Build Coastguard Worker 
addBind(std::string_view what,std::string_view where)167*9190c2a8SAndroid Build Coastguard Worker void MountRegistry::Mounts::addBind(std::string_view what, std::string_view where) {
168*9190c2a8SAndroid Build Coastguard Worker     auto whatAbsolute = path::normalize(what);
169*9190c2a8SAndroid Build Coastguard Worker     auto [root, rootIt] = rootIndex(whatAbsolute);
170*9190c2a8SAndroid Build Coastguard Worker     if (root < 0) {
171*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << "[incfs] No root found for bind from " << what << " to " << where;
172*9190c2a8SAndroid Build Coastguard Worker         return;
173*9190c2a8SAndroid Build Coastguard Worker     }
174*9190c2a8SAndroid Build Coastguard Worker 
175*9190c2a8SAndroid Build Coastguard Worker     const auto& currentBind = rootIt->first;
176*9190c2a8SAndroid Build Coastguard Worker     auto whatSubpath = path::relativize(currentBind, whatAbsolute);
177*9190c2a8SAndroid Build Coastguard Worker     const auto& subdir = rootIt->second.subdir;
178*9190c2a8SAndroid Build Coastguard Worker     auto realSubdir = path::join(subdir, whatSubpath);
179*9190c2a8SAndroid Build Coastguard Worker     auto it = rootByBindPoint
180*9190c2a8SAndroid Build Coastguard Worker                       .insert_or_assign(path::normalize(where), Bind{std::move(realSubdir), root})
181*9190c2a8SAndroid Build Coastguard Worker                       .first;
182*9190c2a8SAndroid Build Coastguard Worker     roots[root].binds.push_back(it);
183*9190c2a8SAndroid Build Coastguard Worker }
184*9190c2a8SAndroid Build Coastguard Worker 
removeBind(std::string_view what)185*9190c2a8SAndroid Build Coastguard Worker void MountRegistry::Mounts::removeBind(std::string_view what) {
186*9190c2a8SAndroid Build Coastguard Worker     auto absolute = path::normalize(what);
187*9190c2a8SAndroid Build Coastguard Worker     auto [root, rootIt] = rootIndex(absolute);
188*9190c2a8SAndroid Build Coastguard Worker     if (root < 0) {
189*9190c2a8SAndroid Build Coastguard Worker         LOG(WARNING) << "[incfs] Trying to remove non-existent bind point '" << what << '\'';
190*9190c2a8SAndroid Build Coastguard Worker         return;
191*9190c2a8SAndroid Build Coastguard Worker     }
192*9190c2a8SAndroid Build Coastguard Worker     if (roots[root].path == absolute) {
193*9190c2a8SAndroid Build Coastguard Worker         removeRoot(absolute);
194*9190c2a8SAndroid Build Coastguard Worker         return;
195*9190c2a8SAndroid Build Coastguard Worker     }
196*9190c2a8SAndroid Build Coastguard Worker 
197*9190c2a8SAndroid Build Coastguard Worker     rootByBindPoint.erase(rootIt);
198*9190c2a8SAndroid Build Coastguard Worker     auto& binds = roots[root].binds;
199*9190c2a8SAndroid Build Coastguard Worker     auto itBind = std::find(binds.begin(), binds.end(), rootIt);
200*9190c2a8SAndroid Build Coastguard Worker     std::swap(binds.back(), *itBind);
201*9190c2a8SAndroid Build Coastguard Worker     binds.pop_back();
202*9190c2a8SAndroid Build Coastguard Worker }
203*9190c2a8SAndroid Build Coastguard Worker 
MountRegistry(std::string_view filesystem)204*9190c2a8SAndroid Build Coastguard Worker MountRegistry::MountRegistry(std::string_view filesystem)
205*9190c2a8SAndroid Build Coastguard Worker       : mFilesystem(filesystem.empty() ? INCFS_NAME : filesystem),
206*9190c2a8SAndroid Build Coastguard Worker         mMountInfo(::open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC)) {
207*9190c2a8SAndroid Build Coastguard Worker     if (!mMountInfo.ok()) {
208*9190c2a8SAndroid Build Coastguard Worker         PLOG(FATAL) << "Failed to open the /proc/mounts file";
209*9190c2a8SAndroid Build Coastguard Worker     }
210*9190c2a8SAndroid Build Coastguard Worker     mMounts.loadFrom(mMountInfo, mFilesystem);
211*9190c2a8SAndroid Build Coastguard Worker }
212*9190c2a8SAndroid Build Coastguard Worker 
213*9190c2a8SAndroid Build Coastguard Worker MountRegistry::~MountRegistry() = default;
214*9190c2a8SAndroid Build Coastguard Worker 
rootFor(std::string_view path)215*9190c2a8SAndroid Build Coastguard Worker std::string MountRegistry::rootFor(std::string_view path) {
216*9190c2a8SAndroid Build Coastguard Worker     auto lock = ensureUpToDate();
217*9190c2a8SAndroid Build Coastguard Worker     return std::string(mMounts.rootFor(path));
218*9190c2a8SAndroid Build Coastguard Worker }
219*9190c2a8SAndroid Build Coastguard Worker 
detailsFor(std::string_view path)220*9190c2a8SAndroid Build Coastguard Worker auto MountRegistry::detailsFor(std::string_view path) -> Details {
221*9190c2a8SAndroid Build Coastguard Worker     auto lock = ensureUpToDate();
222*9190c2a8SAndroid Build Coastguard Worker     auto [root, subpath] = mMounts.rootAndSubpathFor(path);
223*9190c2a8SAndroid Build Coastguard Worker     if (!root) {
224*9190c2a8SAndroid Build Coastguard Worker         return {};
225*9190c2a8SAndroid Build Coastguard Worker     }
226*9190c2a8SAndroid Build Coastguard Worker     return {root->path, root->backing, subpath};
227*9190c2a8SAndroid Build Coastguard Worker }
228*9190c2a8SAndroid Build Coastguard Worker 
rootAndSubpathFor(std::string_view path)229*9190c2a8SAndroid Build Coastguard Worker std::pair<std::string, std::string> MountRegistry::rootAndSubpathFor(std::string_view path) {
230*9190c2a8SAndroid Build Coastguard Worker     auto lock = ensureUpToDate();
231*9190c2a8SAndroid Build Coastguard Worker     auto [root, subpath] = mMounts.rootAndSubpathFor(path);
232*9190c2a8SAndroid Build Coastguard Worker     if (!root) {
233*9190c2a8SAndroid Build Coastguard Worker         return {};
234*9190c2a8SAndroid Build Coastguard Worker     }
235*9190c2a8SAndroid Build Coastguard Worker     return {std::string(root->path), std::move(subpath)};
236*9190c2a8SAndroid Build Coastguard Worker }
237*9190c2a8SAndroid Build Coastguard Worker 
copyMounts()238*9190c2a8SAndroid Build Coastguard Worker MountRegistry::Mounts MountRegistry::copyMounts() {
239*9190c2a8SAndroid Build Coastguard Worker     auto lock = ensureUpToDate();
240*9190c2a8SAndroid Build Coastguard Worker     return mMounts;
241*9190c2a8SAndroid Build Coastguard Worker }
242*9190c2a8SAndroid Build Coastguard Worker 
reload()243*9190c2a8SAndroid Build Coastguard Worker void MountRegistry::reload() {
244*9190c2a8SAndroid Build Coastguard Worker     (void)ensureUpToDate();
245*9190c2a8SAndroid Build Coastguard Worker }
246*9190c2a8SAndroid Build Coastguard Worker 
ensureUpToDate()247*9190c2a8SAndroid Build Coastguard Worker std::unique_lock<std::mutex> MountRegistry::ensureUpToDate() {
248*9190c2a8SAndroid Build Coastguard Worker     pollfd pfd = {.fd = mMountInfo.get(), .events = POLLERR | POLLPRI};
249*9190c2a8SAndroid Build Coastguard Worker     const auto res = TEMP_FAILURE_RETRY(poll(&pfd, 1, 0));
250*9190c2a8SAndroid Build Coastguard Worker     if (res == 0) {
251*9190c2a8SAndroid Build Coastguard Worker         // timeout - nothing to do, up to date
252*9190c2a8SAndroid Build Coastguard Worker         return std::unique_lock{mDataMutex};
253*9190c2a8SAndroid Build Coastguard Worker     }
254*9190c2a8SAndroid Build Coastguard Worker 
255*9190c2a8SAndroid Build Coastguard Worker     // reload even if poll() fails: (1) it usually doesn't and (2) it's better to be safe.
256*9190c2a8SAndroid Build Coastguard Worker     std::unique_lock lock(mDataMutex);
257*9190c2a8SAndroid Build Coastguard Worker     mMounts.loadFrom(mMountInfo, mFilesystem);
258*9190c2a8SAndroid Build Coastguard Worker     return lock;
259*9190c2a8SAndroid Build Coastguard Worker }
260*9190c2a8SAndroid Build Coastguard Worker 
261*9190c2a8SAndroid Build Coastguard Worker template <class Callback>
forEachLine(base::borrowed_fd fd,Callback && cb)262*9190c2a8SAndroid Build Coastguard Worker static bool forEachLine(base::borrowed_fd fd, Callback&& cb) {
263*9190c2a8SAndroid Build Coastguard Worker     static constexpr auto kBufSize = 128 * 1024;
264*9190c2a8SAndroid Build Coastguard Worker     char buffer[kBufSize];
265*9190c2a8SAndroid Build Coastguard Worker     const char* nextLine = buffer;
266*9190c2a8SAndroid Build Coastguard Worker     char* nextRead = buffer;
267*9190c2a8SAndroid Build Coastguard Worker     int64_t pos = 0;
268*9190c2a8SAndroid Build Coastguard Worker     for (;;) {
269*9190c2a8SAndroid Build Coastguard Worker         const auto read = pread(fd.get(), nextRead, std::end(buffer) - nextRead, pos);
270*9190c2a8SAndroid Build Coastguard Worker         if (read == 0) {
271*9190c2a8SAndroid Build Coastguard Worker             break;
272*9190c2a8SAndroid Build Coastguard Worker         }
273*9190c2a8SAndroid Build Coastguard Worker         if (read < 0) {
274*9190c2a8SAndroid Build Coastguard Worker             if (errno == EINTR) {
275*9190c2a8SAndroid Build Coastguard Worker                 continue;
276*9190c2a8SAndroid Build Coastguard Worker             }
277*9190c2a8SAndroid Build Coastguard Worker             return false;
278*9190c2a8SAndroid Build Coastguard Worker         }
279*9190c2a8SAndroid Build Coastguard Worker 
280*9190c2a8SAndroid Build Coastguard Worker         pos += read;
281*9190c2a8SAndroid Build Coastguard Worker         const auto readEnd = nextRead + read;
282*9190c2a8SAndroid Build Coastguard Worker         auto chunk = std::string_view{nextLine, size_t(readEnd - nextLine)};
283*9190c2a8SAndroid Build Coastguard Worker         do {
284*9190c2a8SAndroid Build Coastguard Worker             auto lineEnd = chunk.find('\n');
285*9190c2a8SAndroid Build Coastguard Worker             if (lineEnd == chunk.npos) {
286*9190c2a8SAndroid Build Coastguard Worker                 break;
287*9190c2a8SAndroid Build Coastguard Worker             }
288*9190c2a8SAndroid Build Coastguard Worker             cb(chunk.substr(0, lineEnd));
289*9190c2a8SAndroid Build Coastguard Worker             chunk.remove_prefix(lineEnd + 1);
290*9190c2a8SAndroid Build Coastguard Worker         } while (!chunk.empty());
291*9190c2a8SAndroid Build Coastguard Worker 
292*9190c2a8SAndroid Build Coastguard Worker         const auto remainingSize = readEnd - chunk.end();
293*9190c2a8SAndroid Build Coastguard Worker         memmove(buffer, chunk.end(), remainingSize);
294*9190c2a8SAndroid Build Coastguard Worker         nextLine = buffer;
295*9190c2a8SAndroid Build Coastguard Worker         nextRead = buffer + remainingSize;
296*9190c2a8SAndroid Build Coastguard Worker     }
297*9190c2a8SAndroid Build Coastguard Worker 
298*9190c2a8SAndroid Build Coastguard Worker     if (nextLine < nextRead) {
299*9190c2a8SAndroid Build Coastguard Worker         cb({nextLine, size_t(nextRead - nextLine)});
300*9190c2a8SAndroid Build Coastguard Worker     }
301*9190c2a8SAndroid Build Coastguard Worker 
302*9190c2a8SAndroid Build Coastguard Worker     return true;
303*9190c2a8SAndroid Build Coastguard Worker }
304*9190c2a8SAndroid Build Coastguard Worker 
fixBackingDir(std::string_view dir,std::string_view mountDir)305*9190c2a8SAndroid Build Coastguard Worker static std::string fixBackingDir(std::string_view dir, std::string_view mountDir) {
306*9190c2a8SAndroid Build Coastguard Worker     if (!dir.starts_with("/proc/"sv)) {
307*9190c2a8SAndroid Build Coastguard Worker         return std::string(dir);
308*9190c2a8SAndroid Build Coastguard Worker     }
309*9190c2a8SAndroid Build Coastguard Worker 
310*9190c2a8SAndroid Build Coastguard Worker     // HACK:
311*9190c2a8SAndroid Build Coastguard Worker     // Vold uses a secure way of mounting incremental storages, where it passes in
312*9190c2a8SAndroid Build Coastguard Worker     // a virtual symlink in /proc/self/fd/... instead of the original path. Unfortunately,
313*9190c2a8SAndroid Build Coastguard Worker     // this symlink string gets preserved by the system and we can't resolve it later.
314*9190c2a8SAndroid Build Coastguard Worker     // But it's the only place that uses this symlink, and we know exactly how the
315*9190c2a8SAndroid Build Coastguard Worker     // mount and backing directory paths look in that case - so can recover one from
316*9190c2a8SAndroid Build Coastguard Worker     // another.
317*9190c2a8SAndroid Build Coastguard Worker     if (path::endsWith(mountDir, "mount"sv)) {
318*9190c2a8SAndroid Build Coastguard Worker         return path::join(path::dirName(mountDir), "backing_store"sv);
319*9190c2a8SAndroid Build Coastguard Worker     }
320*9190c2a8SAndroid Build Coastguard Worker     // Well, hack didn't work. Still may not return a /proc/ path
321*9190c2a8SAndroid Build Coastguard Worker     return {};
322*9190c2a8SAndroid Build Coastguard Worker }
323*9190c2a8SAndroid Build Coastguard Worker 
loadFrom(base::borrowed_fd fd,std::string_view filesystem)324*9190c2a8SAndroid Build Coastguard Worker bool MountRegistry::Mounts::loadFrom(base::borrowed_fd fd, std::string_view filesystem) {
325*9190c2a8SAndroid Build Coastguard Worker     struct MountInfo {
326*9190c2a8SAndroid Build Coastguard Worker         std::string backing;
327*9190c2a8SAndroid Build Coastguard Worker         std::set<std::string, std::less<>> roots;
328*9190c2a8SAndroid Build Coastguard Worker         std::vector<std::pair<std::string, std::string>> bindPoints;
329*9190c2a8SAndroid Build Coastguard Worker     };
330*9190c2a8SAndroid Build Coastguard Worker     std::unordered_map<std::string, MountInfo> mountsByGroup(16);
331*9190c2a8SAndroid Build Coastguard Worker     std::vector<std::string_view> items(12);
332*9190c2a8SAndroid Build Coastguard Worker     const auto parsed = forEachLine(fd, [&](std::string_view line) {
333*9190c2a8SAndroid Build Coastguard Worker         if (line.empty()) {
334*9190c2a8SAndroid Build Coastguard Worker             return;
335*9190c2a8SAndroid Build Coastguard Worker         }
336*9190c2a8SAndroid Build Coastguard Worker         Split(line, ' ', &items);
337*9190c2a8SAndroid Build Coastguard Worker         if (items.size() < 10) {
338*9190c2a8SAndroid Build Coastguard Worker             LOG(WARNING) << "[incfs] bad line in mountinfo: '" << line << '\'';
339*9190c2a8SAndroid Build Coastguard Worker             return;
340*9190c2a8SAndroid Build Coastguard Worker         }
341*9190c2a8SAndroid Build Coastguard Worker         // Note: there are optional fields in the line, starting at [6]. Anything after that should
342*9190c2a8SAndroid Build Coastguard Worker         // be indexed from the end.
343*9190c2a8SAndroid Build Coastguard Worker         const auto name = items.rbegin()[2];
344*9190c2a8SAndroid Build Coastguard Worker         if (!name.starts_with(filesystem)) {
345*9190c2a8SAndroid Build Coastguard Worker             return;
346*9190c2a8SAndroid Build Coastguard Worker         }
347*9190c2a8SAndroid Build Coastguard Worker         const auto groupId = items[2];
348*9190c2a8SAndroid Build Coastguard Worker         auto subdir = items[3];
349*9190c2a8SAndroid Build Coastguard Worker         auto mountPoint = std::string(items[4]);
350*9190c2a8SAndroid Build Coastguard Worker         fixProcPath(mountPoint);
351*9190c2a8SAndroid Build Coastguard Worker         mountPoint = path::normalize(mountPoint);
352*9190c2a8SAndroid Build Coastguard Worker         auto& mount = mountsByGroup[std::string(groupId)];
353*9190c2a8SAndroid Build Coastguard Worker         auto backingDir = fixBackingDir(items.rbegin()[1], mountPoint);
354*9190c2a8SAndroid Build Coastguard Worker         if (!backingDir.empty()) {
355*9190c2a8SAndroid Build Coastguard Worker             if (mount.backing.empty()) {
356*9190c2a8SAndroid Build Coastguard Worker                 mount.backing = std::move(backingDir);
357*9190c2a8SAndroid Build Coastguard Worker             } else if (mount.backing != backingDir) {
358*9190c2a8SAndroid Build Coastguard Worker                 LOG(WARNING) << "[incfs] root '"
359*9190c2a8SAndroid Build Coastguard Worker                              << (!mount.roots.empty() ? *mount.roots.begin() : "<unknown>")
360*9190c2a8SAndroid Build Coastguard Worker                              << "' mounted in multiple places with different backing dirs, '"
361*9190c2a8SAndroid Build Coastguard Worker                              << mount.backing << "' vs new '" << backingDir
362*9190c2a8SAndroid Build Coastguard Worker                              << "'; updating to the new one";
363*9190c2a8SAndroid Build Coastguard Worker                 mount.backing = std::move(backingDir);
364*9190c2a8SAndroid Build Coastguard Worker             }
365*9190c2a8SAndroid Build Coastguard Worker         }
366*9190c2a8SAndroid Build Coastguard Worker         if (subdir == "/"sv) {
367*9190c2a8SAndroid Build Coastguard Worker             mount.roots.emplace(mountPoint);
368*9190c2a8SAndroid Build Coastguard Worker             subdir = ""sv;
369*9190c2a8SAndroid Build Coastguard Worker         }
370*9190c2a8SAndroid Build Coastguard Worker         mount.bindPoints.emplace_back(std::string(subdir), std::move(mountPoint));
371*9190c2a8SAndroid Build Coastguard Worker     });
372*9190c2a8SAndroid Build Coastguard Worker 
373*9190c2a8SAndroid Build Coastguard Worker     if (!parsed) {
374*9190c2a8SAndroid Build Coastguard Worker         return false;
375*9190c2a8SAndroid Build Coastguard Worker     }
376*9190c2a8SAndroid Build Coastguard Worker 
377*9190c2a8SAndroid Build Coastguard Worker     rootByBindPoint.clear();
378*9190c2a8SAndroid Build Coastguard Worker     // preserve the allocated capacity, but clear existing data
379*9190c2a8SAndroid Build Coastguard Worker     roots.resize(mountsByGroup.size());
380*9190c2a8SAndroid Build Coastguard Worker     for (auto& root : roots) {
381*9190c2a8SAndroid Build Coastguard Worker         root.binds.clear();
382*9190c2a8SAndroid Build Coastguard Worker     }
383*9190c2a8SAndroid Build Coastguard Worker 
384*9190c2a8SAndroid Build Coastguard Worker     int index = 0;
385*9190c2a8SAndroid Build Coastguard Worker     for (auto& [_, mount] : mountsByGroup) {
386*9190c2a8SAndroid Build Coastguard Worker         if (mount.roots.empty()) {
387*9190c2a8SAndroid Build Coastguard Worker             // the mount has no root, and without root we have no good way of accessing the
388*9190c2a8SAndroid Build Coastguard Worker             // control files - so the only valid reaction here is to ignore it
389*9190c2a8SAndroid Build Coastguard Worker             LOG(WARNING) << "[incfs] mount '" << mount.backing << "' has no root, but "
390*9190c2a8SAndroid Build Coastguard Worker                          << mount.bindPoints.size() << " bind(s), ignoring";
391*9190c2a8SAndroid Build Coastguard Worker             continue;
392*9190c2a8SAndroid Build Coastguard Worker         }
393*9190c2a8SAndroid Build Coastguard Worker         if (mount.backing.empty()) {
394*9190c2a8SAndroid Build Coastguard Worker             LOG(WARNING) << "[incfs] mount '" << *mount.roots.begin()
395*9190c2a8SAndroid Build Coastguard Worker                          << "' has no backing dir, but " << mount.bindPoints.size()
396*9190c2a8SAndroid Build Coastguard Worker                          << " bind(s), ignoring";
397*9190c2a8SAndroid Build Coastguard Worker             continue;
398*9190c2a8SAndroid Build Coastguard Worker         }
399*9190c2a8SAndroid Build Coastguard Worker 
400*9190c2a8SAndroid Build Coastguard Worker         Root& root = roots[index];
401*9190c2a8SAndroid Build Coastguard Worker         auto& binds = root.binds;
402*9190c2a8SAndroid Build Coastguard Worker         binds.reserve(mount.bindPoints.size());
403*9190c2a8SAndroid Build Coastguard Worker         for (auto& [subdir, bind] : mount.bindPoints) {
404*9190c2a8SAndroid Build Coastguard Worker             auto it = rootByBindPoint
405*9190c2a8SAndroid Build Coastguard Worker                               .insert_or_assign(std::move(bind), Bind{std::move(subdir), index})
406*9190c2a8SAndroid Build Coastguard Worker                               .first;
407*9190c2a8SAndroid Build Coastguard Worker             binds.push_back(it);
408*9190c2a8SAndroid Build Coastguard Worker         }
409*9190c2a8SAndroid Build Coastguard Worker         root.backing = std::move(mount.backing);
410*9190c2a8SAndroid Build Coastguard Worker         fixProcPath(root.backing);
411*9190c2a8SAndroid Build Coastguard Worker 
412*9190c2a8SAndroid Build Coastguard Worker         // a trick here: given that as of now we either have exactly one root, or the preferred one
413*9190c2a8SAndroid Build Coastguard Worker         // is always at the front, let's pick that one here.
414*9190c2a8SAndroid Build Coastguard Worker         root.path = std::move(mount.roots.extract(mount.roots.begin()).value());
415*9190c2a8SAndroid Build Coastguard Worker         ++index;
416*9190c2a8SAndroid Build Coastguard Worker     }
417*9190c2a8SAndroid Build Coastguard Worker     roots.resize(index);
418*9190c2a8SAndroid Build Coastguard Worker 
419*9190c2a8SAndroid Build Coastguard Worker     LOG(INFO) << "[incfs] Loaded " << filesystem << " mount info: " << roots.size()
420*9190c2a8SAndroid Build Coastguard Worker               << " instances, " << rootByBindPoint.size() << " mount points";
421*9190c2a8SAndroid Build Coastguard Worker     if (base::VERBOSE >= base::GetMinimumLogSeverity()) {
422*9190c2a8SAndroid Build Coastguard Worker         for (auto&& [root, backing, binds] : roots) {
423*9190c2a8SAndroid Build Coastguard Worker             LOG(INFO) << "[incfs]  '" << root << '\'';
424*9190c2a8SAndroid Build Coastguard Worker             LOG(INFO) << "[incfs]    backing: '" << backing << '\'';
425*9190c2a8SAndroid Build Coastguard Worker             for (auto&& bind : binds) {
426*9190c2a8SAndroid Build Coastguard Worker                 LOG(INFO) << "[incfs]      bind : '" << bind->second.subdir << "'->'" << bind->first
427*9190c2a8SAndroid Build Coastguard Worker                           << '\'';
428*9190c2a8SAndroid Build Coastguard Worker             }
429*9190c2a8SAndroid Build Coastguard Worker         }
430*9190c2a8SAndroid Build Coastguard Worker     }
431*9190c2a8SAndroid Build Coastguard Worker     return true;
432*9190c2a8SAndroid Build Coastguard Worker }
433*9190c2a8SAndroid Build Coastguard Worker 
load(base::borrowed_fd mountInfo,std::string_view filesystem)434*9190c2a8SAndroid Build Coastguard Worker auto MountRegistry::Mounts::load(base::borrowed_fd mountInfo, std::string_view filesystem)
435*9190c2a8SAndroid Build Coastguard Worker         -> Mounts {
436*9190c2a8SAndroid Build Coastguard Worker     Mounts res;
437*9190c2a8SAndroid Build Coastguard Worker     res.loadFrom(mountInfo, filesystem);
438*9190c2a8SAndroid Build Coastguard Worker     return res;
439*9190c2a8SAndroid Build Coastguard Worker }
440*9190c2a8SAndroid Build Coastguard Worker 
441*9190c2a8SAndroid Build Coastguard Worker } // namespace android::incfs
442