Skip to content

Commit

Permalink
add umount hook for udisks
Browse files Browse the repository at this point in the history
  • Loading branch information
XUranus committed Mar 30, 2024
1 parent 27e9826 commit f5b4ba6
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
17 changes: 17 additions & 0 deletions include/native/linux/LinuxMountUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,45 @@
namespace volumeprotect {
namespace linuxmountutil {

// entry of /proc/mounts
struct MountEntry {
std::string devicePath;
std::string mountTargetPath;
std::string type;
std::string options;
};

// a single implement
bool Mount(
const std::string& devicePath,
const std::string& mountTargetPath,
const std::string& fsType,
const std::string& mountOptions,
bool readOnly);

// a more complicate implement, automatically parse the options into flags
bool Mount2(
const std::string& devicePath,
const std::string& mountTargetPath,
const std::string& fsType,
const std::string& mountOptions,
bool readOnly);

// umount one mount point
bool Umount(const std::string& mountTargetPath, bool force);

// umount all mount points releated to the device by force
bool UmountAll(const std::string& devicePath);

// return if the directory path is a mount point
bool IsMountPoint(const std::string& dirPath);

// get the block device path of the mount point
std::string GetMountDevicePath(const std::string& mountTargetPath);

// get all mount points of a device
std::vector<MountEntry> GetAllMounts(const std::string& devicePath);

}
}

Expand Down
4 changes: 4 additions & 0 deletions src/native/linux/LinuxDeviceMapperMountProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,10 @@ bool LinuxDeviceMapperUmountProvider::Umount()
RECORD_INNER_ERROR("failed to umount target %s, errno %u", m_mountTargetPath.c_str(), errno);
success = false;
}
if (!linuxmountutil::UmountAll(m_dmDeviceName)) {
RECORD_INNER_ERROR("failed to umount all mounts of %s", m_dmDeviceName.c_str());
success = false;
}
// check if need to remove dm device
if (!m_dmDeviceName.empty() && !devicemapper::RemoveDeviceIfExists(m_dmDeviceName)) {
RECORD_INNER_ERROR("failed to remove devicemapper device %s, errno", m_dmDeviceName.c_str(), errno);
Expand Down
4 changes: 4 additions & 0 deletions src/native/linux/LinuxLoopbackMountProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ bool LinuxLoopbackUmountProvider::Umount()
RECORD_INNER_ERROR("failed to umount target %s, errno %u", m_mountTargetPath.c_str(), errno);
return false;
}
if (!linuxmountutil::UmountAll(m_loopbackDevicePath)) {
RECORD_INNER_ERROR("failed to umount all mounts of %s", m_loopbackDevicePath.c_str());
return false;
}
// 2. detach loopback device
if (!m_loopbackDevicePath.empty()
&& loopback::Attached(m_loopbackDevicePath)
Expand Down
44 changes: 44 additions & 0 deletions src/native/linux/LinuxMountUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace {
const int MNTENT_BUFFER_MAX = 4096;
const std::string SYS_MOUNTS_ENTRY_PATH = "/proc/mounts";
const int MAX_MOUNT_RETRY = 3;
const int MAX_UMOUNT_RETRY = 3;
}

using namespace volumeprotect;
Expand Down Expand Up @@ -209,6 +210,32 @@ bool linuxmountutil::Umount(const std::string& mountTargetPath, bool force)
return true;
}

/**
* some linux desktop environment distro may running services like udisks2,
* that may mount the created loop device onto path /run/media/$user/uuid.
* To prevent residual mounts caused by such service, UmountAll() will try several
* times to try to umount all releated mounts of the device.
*/
bool linuxmountutil::UmountAll(const std::string& devicePath)
{
std::vector<MountEntry> entries = linuxmountutil::GetAllMounts(devicePath);
int retry = 0;
while (!entries.empty() && retry < MAX_UMOUNT_RETRY) {
for (const auto& entry : entries) {
// this umount will not stucked
::umount2(entry.mountTargetPath.c_str(), (MNT_FORCE | MNT_DETACH));
}
retry++;
entries = linuxmountutil::GetAllMounts(devicePath);
}
if (!entries.empty()) {
ERRLOG("%d mount entries remain mounted! failed to clean all mounts for %s",
entries.size(), devicePath.c_str());
return false;
}
return true;
}

bool linuxmountutil::IsMountPoint(const std::string& dirPath)
{
bool mounted = false;
Expand Down Expand Up @@ -249,4 +276,21 @@ std::string linuxmountutil::GetMountDevicePath(const std::string& mountTargetPat
return devicePath;
}

std::vector<MountEntry> linuxmountutil::GetAllMounts(const std::string& devicePath)
{
std::vector<MountEntry> entries {};
FILE* mountsFile = ::setmntent(SYS_MOUNTS_ENTRY_PATH.c_str(), "r");
if (mountsFile == nullptr) {
ERRLOG("failed to open /proc/mounts, errno %u", errno);
return {};
}
struct mntent entry {};
char mntentBuffer[MNTENT_BUFFER_MAX] = { 0 };
while (::getmntent_r(mountsFile, &entry, mntentBuffer, MNTENT_BUFFER_MAX) != nullptr) {
entries.emplace_back(MountEntry {entry.mnt_fsname, entry.mnt_dir, entry.mnt_type, entry.mnt_opts });
}
::endmntent(mountsFile);
return entries;
}

#endif

0 comments on commit f5b4ba6

Please sign in to comment.