InternalEncryption: make umount logic more error proof 28/144428/5
authorLukasz Pawelczyk <l.pawelczyk@samsung.com>
Wed, 16 Aug 2017 15:26:06 +0000 (17:26 +0200)
committerLukasz Pawelczyk <l.pawelczyk@samsung.com>
Mon, 11 Sep 2017 11:26:20 +0000 (13:26 +0200)
Don't umount if the device is not already mounted.
Try to umount if the device is mounted more then once (bind).

Change-Id: I0656146225fb0df429a4da1af743bc1d1cbdb9f9

server/internal-encryption.cpp

index 7704078..11a6c1a 100644 (file)
 #include <unistd.h>
 #include <sys/mount.h>
 #include <sys/reboot.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <limits.h>
+#include <stdlib.h>
 
 #include <vconf.h>
 #include <tzplatform_config.h>
@@ -61,6 +65,56 @@ namespace ode {
 
 namespace {
 
+std::string findDevPath()
+{
+       std::string source = INTERNAL_DEV_PATH "/" INTERNAL_DEV_NAME;
+       try {
+               runtime::DirectoryIterator iter(INTERNAL_DEV_PATH), end;
+
+               while (iter != end) {
+                       const std::string& path = (*iter).getPath();
+                       std::string name = path.substr(path.rfind('/') + 1);
+                       std::string upper;
+                       upper.reserve(name.size());
+                       for (char c : name) {
+                               upper += std::toupper(c);
+                       }
+                       if (upper == INTERNAL_DEV_NAME) {
+                               source = path;
+                               break;
+                       }
+                       ++iter;
+               }
+       } catch (runtime::Exception &e) {}
+
+       char *dev = ::realpath(source.c_str(), NULL);
+       if (dev == NULL) {
+               throw runtime::Exception("Failed to find device path.");
+       }
+
+       std::string devPath(dev);
+       free(dev);
+
+       return devPath;
+}
+
+std::string findMntPath(const std::string &devPath)
+{
+       std::string ret;
+
+       FILE* mtab = ::setmntent("/etc/mtab", "r");
+       struct mntent* entry = NULL;
+       while ((entry = ::getmntent(mtab)) != NULL) {
+               if (devPath == entry->mnt_fsname) {
+                       ret = entry->mnt_dir;
+                       break;
+               }
+       }
+       ::endmntent(mtab);
+
+       return ret;
+}
+
 std::unique_ptr<INTERNAL_ENGINE> engine;
 KeyManager::data mountKey;
 
@@ -215,25 +269,7 @@ InternalEncryption::InternalEncryption(ODEControlContext& ctx) :
 
        context.createNotification("InternalEncryption::mount");
 
-       std::string source = INTERNAL_DEV_PATH "/" INTERNAL_DEV_NAME;
-       try {
-               runtime::DirectoryIterator iter(INTERNAL_DEV_PATH), end;
-
-               while (iter != end) {
-                       const std::string& path = (*iter).getPath();
-                       std::string name = path.substr(path.rfind('/') + 1);
-                       std::string upper;
-                       upper.reserve(name.size());
-                       for (char c : name) {
-                               upper += std::toupper(c);
-                       }
-                       if (upper == INTERNAL_DEV_NAME) {
-                               source = path;
-                               break;
-                       }
-                       ++iter;
-               }
-       } catch (runtime::Exception &e) {}
+       std::string source = findDevPath();
 
        engine.reset(new INTERNAL_ENGINE(
                source, INTERNAL_PATH,
@@ -329,18 +365,27 @@ int InternalEncryption::encrypt(const std::string& password, unsigned int option
        KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
        auto encryptWorker = [MasterKey, options, this]() {
                try {
-                       INFO(SINK, "Close all known systemd services that might be using internal storage...");
-                       stopKnownSystemdServices();
-                       INFO(SINK, "Close all processes using internal storage...");
-                       stopDependedSystemdServices();
-                       INFO(SINK, "Umount internal storage...");
-                       while (::umount(INTERNAL_PATH) == -1) {
-                               if (errno != EBUSY) {
-                                       throw runtime::Exception("Umount error - " + std::to_string(errno));
-                               }
+                       std::string source = engine->getSource();
+                       std::string mntPath = findMntPath(source);
+
+                       if (!mntPath.empty()) {
+                               INFO(SINK, "Close all known systemd services that might be using internal storage...");
+                               stopKnownSystemdServices();
+                               INFO(SINK, "Close all processes using internal storage...");
                                stopDependedSystemdServices();
                        }
 
+                       while (!mntPath.empty()) {
+                               INFO(SINK, "Umount internal storage...");
+                               while (::umount(mntPath.c_str()) == -1) {
+                                       if (errno != EBUSY) {
+                                               throw runtime::Exception("Umount error - " + std::to_string(errno));
+                                       }
+                                       stopDependedSystemdServices();
+                               }
+                               mntPath = findMntPath(source);
+                       }
+
                        showProgressUI("Encrypting");
 
                        INFO(SINK, "Encryption started...");
@@ -382,17 +427,20 @@ int InternalEncryption::decrypt(const std::string& password)
        KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
        auto decryptWorker = [MasterKey, this]() {
                try {
-                       INFO(SINK, "Close all known systemd services that might be using internal storage...");
-                       stopKnownSystemdServices();
-                       INFO(SINK, "Close all processes using internal storage...");
-                       stopDependedSystemdServices();
-                       INFO(SINK, "Umount internal storage...");
-                       while (1) {
-                               try {
-                                       engine->umount();
-                                       break;
-                               } catch (runtime::Exception& e) {
-                                       stopDependedSystemdServices();
+                       if (engine->isMounted()) {
+                               INFO(SINK, "Close all known systemd services that might be using internal storage...");
+                               stopKnownSystemdServices();
+                               INFO(SINK, "Close all processes using internal storage...");
+                               stopDependedSystemdServices();
+
+                               INFO(SINK, "Umount internal storage...");
+                               while (1) {
+                                       try {
+                                               engine->umount();
+                                               break;
+                                       } catch (runtime::Exception& e) {
+                                               stopDependedSystemdServices();
+                                       }
                                }
                        }