@@ -34,54 +34,73 @@ namespace facebook::eden {
3434
3535namespace {
3636
37- bool getSystemMountList (std::string& out) {
38- #ifdef __APPLE__
39- struct statfs * buf;
40- int count = getmntinfo (&buf, MNT_WAIT );
41- if (count == 0 ) {
42- XLOGF (ERR , " getmntinfo failed: {}" , folly::errnoStr (errno));
37+ #ifdef __linux__
38+ /* *
39+ * Callback type for iterating over mount entries.
40+ * Return true to continue iteration, false to stop early.
41+ */
42+ using MountEntryCallback =
43+ std::function<bool (const std::string& fsName, const std::string& mountDir)>;
44+
45+ /* *
46+ * Iterates over the system mount table using setmntent/getmntent.
47+ * Calls the provided callback for each mount entry.
48+ * Returns false if we failed to open the mount table.
49+ */
50+ bool forEachMountEntry (const MountEntryCallback& callback) {
51+ FILE * mtab = setmntent (" /proc/mounts" , " r" );
52+ if (mtab == nullptr ) {
53+ XLOGF (WARN , " Failed to open /proc/mounts: {}" , folly::errnoStr (errno));
4354 return false ;
4455 }
45- for (int i = 0 ; i < count; i++) {
46- out += fmt::format (
47- " {} {} {}\n " ,
48- buf[i].f_mntfromname ,
49- buf[i].f_mntonname ,
50- buf[i].f_fstypename );
56+ SCOPE_EXIT {
57+ endmntent (mtab);
58+ };
59+
60+ struct mntent * entry;
61+ while ((entry = getmntent (mtab)) != nullptr ) {
62+ if (!callback (entry->mnt_fsname , entry->mnt_dir )) {
63+ break ;
64+ }
5165 }
5266 return true ;
53- #else
54- if (folly::readFile (" /proc/mounts" , out)) {
55- return true ;
56- } else {
57- XLOGF (ERR , " failed to read /proc/mounts: {}" , folly::errnoStr (errno));
58- return false ;
59- }
60- #endif
6167}
68+ #endif
6269
63- /* Determines whether the given mountPoint is contained in the mount table
70+ /* *
71+ * Determines whether the given mountPoint is contained in the mount table
6472 * and looks like it was previously mounted by EdenFS.
6573 */
6674bool isOldEdenMount (const std::string& mountPoint) {
67- std::string mounts;
68- if (getSystemMountList (mounts)) {
69- // TODO(T201411922): Update to std::string_view once our macOS build uses
70- // C++20.
71- // https://en.cppreference.com/w/cpp/string/basic_string_view/starts_with
72- std::vector<folly::StringPiece> lines;
73- folly::split (' \n ' , mounts, lines);
74-
75- for (const auto & line : lines) {
76- // We expect EdenFS mounts to look like the following:
77- // edenfs: {mountPoint} fuse ...
78- if (is_edenfs_fs_mount (line, mountPoint)) {
75+ #ifdef __linux__
76+ bool found = false ;
77+ bool success = forEachMountEntry (
78+ [&mountPoint, &found](
79+ const std::string& fsName, const std::string& mountDir) {
80+ if (mountDir == mountPoint && is_edenfs_fs_type (fsName)) {
81+ found = true ;
82+ return false ;
83+ }
84+ return true ;
85+ });
86+
87+ if (success && found) {
88+ return true ;
89+ }
90+ #else
91+ struct statfs * buf;
92+ int count = getmntinfo (&buf, MNT_WAIT );
93+ if (count == 0 ) {
94+ XLOGF (ERR , " getmntinfo failed: {}" , folly::errnoStr (errno));
95+ } else {
96+ for (int i = 0 ; i < count; i++) {
97+ if (std::string (buf[i].f_mntonname ) == mountPoint &&
98+ is_edenfs_fs_type (buf[i].f_fstypename )) {
7999 return true ;
80100 }
81101 }
82102 }
83- // We couldn't verify that the mount is an old, disconnected EdenFS mount.
84- // We assume it isn't to be safe.
103+ #endif
85104 XLOGF (DBG4 , " Could not verify that {} is an old EdenFS mount." , mountPoint);
86105 return false ;
87106}
@@ -171,33 +190,26 @@ void PrivHelperServer::cleanupStaleBindMounts(const std::string& checkoutPath) {
171190 // Parse /proc/mounts to find stale redirection mounts under this checkout.
172191 // These are mounts that EdenFS set up (e.g., buck-out) that were left behind
173192 // when EdenFS crashed without properly unmounting.
174- FILE * mtab = setmntent (" /proc/mounts" , " r" );
175- if (mtab == nullptr ) {
176- XLOGF (WARN , " Failed to open /proc/mounts, skipping redirection cleanup" );
177- return ;
178- }
179- SCOPE_EXIT {
180- endmntent (mtab);
181- };
182-
183193 std::vector<std::string> staleMounts;
184194 std::string checkoutPrefix = checkoutPath + " /" ;
185195
186- struct mntent * entry;
187- while ((entry = getmntent (mtab)) != nullptr ) {
188- std::string mountPoint = entry->mnt_dir ;
189-
190- if (!folly::StringPiece (mountPoint).startsWith (checkoutPrefix)) {
191- continue ;
192- }
196+ bool success = forEachMountEntry (
197+ [&checkoutPrefix, &checkoutPath, &staleMounts](
198+ const std::string& /* fsName*/ , const std::string& mountDir) {
199+ if (folly::StringPiece (mountDir).startsWith (checkoutPrefix)) {
200+ XLOGF (
201+ INFO ,
202+ " Found potential stale redirection mount under {}: {}" ,
203+ checkoutPath,
204+ mountDir);
205+ staleMounts.push_back (mountDir);
206+ }
207+ return true ;
208+ });
193209
194- // This is a mount under our checkout (likely an EdenFS redirection)
195- XLOGF (
196- INFO ,
197- " Found potential stale redirection mount under {}: {}" ,
198- checkoutPath,
199- mountPoint);
200- staleMounts.push_back (std::move (mountPoint));
210+ if (!success) {
211+ XLOGF (WARN , " Skipping redirection cleanup due to mount table read failure" );
212+ return ;
201213 }
202214
203215 // Unmount any stale mounts we found (in reverse order to handle nested
0 commit comments