Refine error/exception handling logic 60/121260/6
authorsangwan.kwon <sangwan.kwon@samsung.com>
Mon, 27 Mar 2017 10:16:46 +0000 (19:16 +0900)
committersangwan.kwon <sangwan.kwon@samsung.com>
Thu, 30 Mar 2017 08:20:24 +0000 (17:20 +0900)
Change-Id: Idf22a826277c872c9a180cfc9196d2193d30d6f7
Signed-off-by: sangwan.kwon <sangwan.kwon@samsung.com>
api/tanchor/error.h
api/tanchor/trust-anchor.h
src/certificate.cpp
src/exception.cpp
src/exception.hxx
src/trust-anchor.cpp

index 68463a3ae83cd77517378d9a9ac341785bdc9fae..443e50cdd2b610ce4ab1ee2f08477f62e4a8e889 100644 (file)
@@ -43,6 +43,8 @@ typedef enum {
        TRUST_ANCHOR_ERROR_NONE = 0,
        TRUST_ANCHOR_ERROR_INVALID_PARAMETER = -EINVAL,
        TRUST_ANCHOR_ERROR_OUT_OF_MEMORY = -ENOMEM,
+       TRUST_ANCHOR_ERROR_PERMISSION_DENIED = -EACCES,
+       TRUST_ANCHOR_ERROR_NO_SUCH_FILE = -ENOENT,
        TRUST_ANCHOR_ERROR_INTERNAL = TRUST_ANCHOR_ERROR_BASE | 0x01
 } trust_anchor_error_e;
 
index 1ba2faa090f13f7ddc948bf43023ce7abd58f303..522073af02e78b08fe0e7914bc0f09e6142be727 100644 (file)
@@ -45,6 +45,9 @@ extern "C" {
  *         negative on error
  * @retval #TRUST_ANCHOR_ERROR_NONE Successful
  * @retval #TRUST_ANCHOR_ERROR_OUT_OF_MEMORY Out of memory error
+ * @retval #TRUST_ANCHOR_ERROR_INVALID_PARAMETER Invalid parameter error
+ * @retval #TRUST_ANCHOR_ERROR_PERMISSION_DENIED Permission denied error
+ * @retval #TRUST_ANCHOR_ERROR_NO_SUCH_FILE No such file or directory error
  * @retval #TRUST_ANCHOR_ERROR_INTERNAL Internal error
  * @see trust_anchor_global_launch()
  * @see trust_anchor_global_uninstall()
@@ -66,6 +69,9 @@ int trust_anchor_global_install(const char *package_id,
  *         negative on error
  * @retval #TRUST_ANCHOR_ERROR_NONE Successful
  * @retval #TRUST_ANCHOR_ERROR_OUT_OF_MEMORY Out of memory error
+ * @retval #TRUST_ANCHOR_ERROR_INVALID_PARAMETER Invalid parameter error
+ * @retval #TRUST_ANCHOR_ERROR_PERMISSION_DENIED Permission denied error
+ * @retval #TRUST_ANCHOR_ERROR_NO_SUCH_FILE No such file or directory error
  * @retval #TRUST_ANCHOR_ERROR_INTERNAL Internal error
  * @see trust_anchor_usr_launch()
  * @see trust_anchor_usr_uninstall()
@@ -86,6 +92,9 @@ int trust_anchor_usr_install(const char *package_id,
  *         negative on error
  * @retval #TRUST_ANCHOR_ERROR_NONE Successful
  * @retval #TRUST_ANCHOR_ERROR_OUT_OF_MEMORY Out of memory error
+ * @retval #TRUST_ANCHOR_ERROR_INVALID_PARAMETER Invalid parameter error
+ * @retval #TRUST_ANCHOR_ERROR_PERMISSION_DENIED Permission denied error
+ * @retval #TRUST_ANCHOR_ERROR_NO_SUCH_FILE No such file or directory error
  * @retval #TRUST_ANCHOR_ERROR_INTERNAL Internal error
  * @see trust_anchor_global_install()
  */
@@ -104,6 +113,9 @@ int trust_anchor_global_launch(const char *package_id,
  *         negative on error
  * @retval #TRUST_ANCHOR_ERROR_NONE Successful
  * @retval #TRUST_ANCHOR_ERROR_OUT_OF_MEMORY Out of memory error
+ * @retval #TRUST_ANCHOR_ERROR_INVALID_PARAMETER Invalid parameter error
+ * @retval #TRUST_ANCHOR_ERROR_PERMISSION_DENIED Permission denied error
+ * @retval #TRUST_ANCHOR_ERROR_NO_SUCH_FILE No such file or directory error
  * @retval #TRUST_ANCHOR_ERROR_INTERNAL Internal error
  * @see trust_anchor_usr_install()
  */
index 0d9bdd52aba5991fef538579bb1452a24ed0ddf3..a0b063ed3e0a60ac2358ebb06e0840d61270db79 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <cstdio>
 #include <vector>
-#include <stdexcept>
+#include "exception.hxx"
 
 #include <openssl/pem.h>
 
@@ -43,10 +43,10 @@ const int HASH_LENGTH = 8;
 } // namespace anonymous
 
 Certificate::Certificate(const std::string &path) :
-       m_fp(FilePtr(fopen(path.c_str(), "rb"), ::fclose))
+       m_fp(FilePtr(::fopen(path.c_str(), "rb"), ::fclose))
 {
        if (this->m_fp == nullptr)
-               throw std::invalid_argument("Faild to open certificate.");
+               throw std::invalid_argument("Failed to open [" + path + "].");
 }
 
 std::string Certificate::getSubjectNameHash() const
index be360ca4bf546cf1bfdca0445adaf65924c69201..9608f9dc1079c98fae73466214b5c27b03fcd56d 100644 (file)
  */
 #include "exception.hxx"
 
-#include <exception>
-
 #include <klay/exception.h>
-#include <klay/audit/logger.h>
 
 namespace tanchor {
 
 int exceptionGuard(const std::function<int()> &func)
 {
-       // TODO add custom error code
        try {
                return func();
-       } catch (runtime::Exception &e) {
+       } catch (const tanchor::Exception &e) {
+               std::string errStr;
+               switch (e.error()) {
+               case ENOENT:
+                       errStr = "No such file or directory.";
+                       break;
+               case ENOMEM:
+                       errStr = "Out of memory.";
+                       break;
+               case EACCES:
+               case EPERM:
+                       errStr = "Permission denied.";
+                       break;
+               default:
+                       errStr = "Internal error.";
+                       break;
+               }
+               ERROR(errStr + e.what());
+               return e.error();
+       } catch (const runtime::Exception &e) {
                ERROR(e.what());
-               return -1;
+               return TRUST_ANCHOR_ERROR_INTERNAL;
        } catch (const std::invalid_argument &e) {
-               ERROR("Invalid argument: " << e.what());
-               return -1;
+               ERROR(e.what());
+               return TRUST_ANCHOR_ERROR_INVALID_PARAMETER;
+       } catch (const std::logic_error &e) {
+               ERROR(e.what());
+               return TRUST_ANCHOR_ERROR_INTERNAL;
        } catch (const std::exception &e) {
                ERROR(e.what());
-               return -1;
+               return TRUST_ANCHOR_ERROR_INTERNAL;
        } catch (...) {
                ERROR("Unknown exception occurred.");
-               return -1;
+               return TRUST_ANCHOR_ERROR_INTERNAL;
        }
 }
 
+Exception::Exception(int ec, const char *file, const char *function,
+                                        unsigned int line, const std::string &message) noexcept :
+       m_ec(ec),
+       m_message(FORMAT("[" << file << ":" << line << " " <<
+                                        function << "()]" << message))
+{
+       ERROR(this->m_message);
+}
+
+const char *Exception::what() const noexcept
+{
+       return this->m_message.c_str();
+}
+
+int Exception::error(void) const noexcept
+{
+       return this->m_ec;
+}
+
 } // namespace tanchor
index 975cb3f26eb75caeb1913a3d7b385762e53fdd35..f0d5350993683354748cef5ff4df804acf4b2085 100644 (file)
  */
 #pragma once
 
+#include "tanchor/error.h"
+
 #include <functional>
+#include <string>
+#include <exception>
+
+#include <klay/audit/logger.h>
 
 #define EXCEPTION_GUARD_START return tanchor::exceptionGuard([&]() {
 #define EXCEPTION_GUARD_END   });
@@ -30,4 +36,39 @@ namespace tanchor {
 
 int exceptionGuard(const std::function<int()> &);
 
+class Exception : public std::exception {
+public:
+       Exception(int ec, const char *file, const char *function,
+                         unsigned int line, const std::string &message) noexcept;
+       virtual ~Exception() = default;
+       virtual const char* what() const noexcept override;
+
+       int error(void) const noexcept;
+
+protected:
+       int m_ec;
+       std::string m_message;
+};
+
 } // namespace tanchor
+
+#define __TANCHOR_THROW(ec, MESSAGE)                     \
+       throw tanchor::Exception(ec, __FILE__, __FUNCTION__, \
+                                                        __LINE__, FORMAT(MESSAGE))
+
+#define ThrowExc(ec, MESSAGE) __TANCHOR_THROW(ec, MESSAGE)
+
+#define ThrowErrno(ec, MESSAGE)                                      \
+       do {                                                             \
+               switch (ec) {                                                \
+               case ENOENT:                                                 \
+                       ThrowExc(TRUST_ANCHOR_ERROR_NO_SUCH_FILE, MESSAGE);      \
+               case ENOMEM:                                                 \
+                       ThrowExc(TRUST_ANCHOR_ERROR_OUT_OF_MEMORY, MESSAGE);     \
+               case EACCES:                                                 \
+               case EPERM:                                                  \
+                       ThrowExc(TRUST_ANCHOR_ERROR_PERMISSION_DENIED, MESSAGE); \
+               default:                                                     \
+                       ThrowExc(TRUST_ANCHOR_ERROR_INTERNAL, MESSAGE);          \
+               }                                                            \
+       } while (0)
index 8f5610e10829df34c7d4609bfdb81462b64a1e9f..52166cccb568e88cd8fd98251175912624e970ca 100644 (file)
@@ -75,6 +75,7 @@ private:
        std::string getUniqueHashName(const std::string &hashName) const;
        std::string getBundleName(void) const;
        bool isSystemCertsModified(void) const;
+       void checkFileValidity(const runtime::File &file) const;
 
        std::string m_packageId;
        std::string m_appCertsPath;
@@ -126,8 +127,7 @@ void TrustAnchor::Impl::linkTo(const std::string &src,
        errno = 0;
        int ret = ::symlink(src.c_str(), dst.c_str());
        if (ret != 0)
-               throw std::logic_error("Fail to link " + src + " -> " + dst +
-                                                          "[" + std::to_string(errno) + "]");
+               ThrowErrno(errno, "Failed to link " + src + " -> " + dst);
 }
 
 void TrustAnchor::Impl::preInstall(void) const
@@ -146,9 +146,10 @@ void TrustAnchor::Impl::preInstall(void) const
        customBundleDir.makeDirectory();
 
        runtime::File appCertsDir(this->m_appCertsPath);
-       if (!appCertsDir.exists() || !appCertsDir.isDirectory())
-               throw std::invalid_argument("App custom certs path is wrong. : " +
-                                                                       m_appCertsPath);
+       this->checkFileValidity(appCertsDir);
+       if (!appCertsDir.isDirectory())
+               throw std::invalid_argument("[" + this->m_appCertsPath +
+                                                                       "] should be directory.");
 
        DEBUG("Success to pre-install stage.");
 }
@@ -188,7 +189,7 @@ int TrustAnchor::Impl::install(bool withSystemCerts) noexcept
 
        INFO("Success to install[" << this->m_packageId <<
                 "] to " << this->m_customBasePath);
-       return 0;
+       return TRUST_ANCHOR_ERROR_NONE;
 
        EXCEPTION_GUARD_END
 }
@@ -199,27 +200,42 @@ int TrustAnchor::Impl::uninstall(bool isRollback) noexcept
 
        runtime::File customBaseDir(this->m_customBasePath);
        if (!customBaseDir.exists() && !isRollback)
-               throw std::invalid_argument("There is no installed anchor previous.");
+               throw std::logic_error("There is no installed anchor previous.");
 
        if (customBaseDir.exists())
                customBaseDir.remove(true);
 
        INFO("Success to uninstall. : " << this->m_packageId);
-       return 0;
+       return TRUST_ANCHOR_ERROR_NONE;
 
        EXCEPTION_GUARD_END
 }
 
+void TrustAnchor::Impl::checkFileValidity(const runtime::File &file) const
+{
+       if (!file.exists())
+               ThrowExc(TRUST_ANCHOR_ERROR_NO_SUCH_FILE,
+                                "File [" << file.getPath() << "] does not exist.");
+
+       if (!file.canRead())
+               ThrowExc(TRUST_ANCHOR_ERROR_PERMISSION_DENIED,
+                                "No permission to read [" << file.getPath() << "]");
+}
+
 bool TrustAnchor::Impl::isSystemCertsModified(void) const
 {
        struct stat systemAttr, customAttr;
 
-       stat(SYS_BUNDLE_PATH.c_str(), &systemAttr);
-       DEBUG("System bundle mtime : " << ::ctime(&systemAttr.st_mtime));
+       errno = 0;
+       if (::stat(SYS_BUNDLE_PATH.c_str(), &systemAttr))
+               ThrowErrno(errno, SYS_BUNDLE_PATH);
 
        auto customBundle = this->m_customBundlePath + "/" + this->getBundleName();
-       stat(customBundle.c_str(), &customAttr);
-       DEBUG("Custom bundle mtime : " << ::ctime(&customAttr.st_mtime));
+       if (::stat(customBundle.c_str(), &customAttr))
+               ThrowErrno(errno, customBundle);
+
+       DEBUG("System bundle mtime : " << ::ctime(&systemAttr.st_mtime) << ", " <<
+                 "Custom bundle mtime : " << ::ctime(&customAttr.st_mtime));
 
        return systemAttr.st_mtime > customAttr.st_mtime;
 }
@@ -234,19 +250,20 @@ int TrustAnchor::Impl::launch(bool withSystemCerts)
        errno = 0;
        // disassociate from the parent namespace
        if (::unshare(CLONE_NEWNS))
-               throw std::logic_error("Failed to unshare namespace > " +
-                                                          std::to_string(errno));
+               ThrowErrno(errno, "Failed to unshare.");
 
        // convert it to a slave for preventing propagation
        if (::mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL))
-               throw std::logic_error("Failed to disconnect root fs.");
+               ThrowErrno(errno, "Failed to mount.");
 
        if (::mount(this->m_customCertsPath.c_str(),
                                MOUNT_POINT_CERTS.c_str(),
                                NULL,
                                MS_BIND,
                                NULL))
-               throw std::logic_error("Failed to mount certs.");
+               ThrowErrno(errno, "Failed to mount. src[" +
+                                                 this->m_customCertsPath + "] to dst[" +
+                                                 MOUNT_POINT_CERTS + "]");
 
        auto bundle = this->m_customBundlePath + "/" + this->getBundleName();
        if (::mount(bundle.c_str(),
@@ -254,10 +271,11 @@ int TrustAnchor::Impl::launch(bool withSystemCerts)
                                NULL,
                                MS_BIND,
                                NULL))
-               throw std::logic_error("Failed to mount bundle.");
+               ThrowErrno(errno, "Failed to mount. src[" + bundle +
+                                                 "] to dst[" + MOUNT_POINT_BUNDLE + "]");
 
        INFO("Success to launch. : " << this->m_packageId);
-       return 0;
+       return TRUST_ANCHOR_ERROR_NONE;
 
        EXCEPTION_GUARD_END
 }
@@ -296,13 +314,11 @@ void TrustAnchor::Impl::makeCustomBundle(bool withSystemCerts)
        DEBUG("Start to migrate previous bundle.");
        if (withSystemCerts) {
                runtime::File sysBundle(SYS_BUNDLE_PATH);
-               if (!sysBundle.exists())
-                       throw std::logic_error("There is no system bundle file.");
+               this->checkFileValidity(sysBundle);
                sysBundle.copyTo(this->m_customBundlePath);
        } else {
                runtime::File tanchorBundle(TANCHOR_BUNDLE_PATH);
-               if (!tanchorBundle.exists())
-                       throw std::logic_error("There is no tanchor bundle file.");
+               this->checkFileValidity(tanchorBundle);
                tanchorBundle.copyTo(this->m_customBundlePath);
        }
        DEBUG("Finish migrating previous bundle.");
@@ -333,7 +349,7 @@ TrustAnchor::TrustAnchor(const std::string &packageId,
        m_pImpl(new Impl(packageId, certsDir, uid)) {}
 
 TrustAnchor::TrustAnchor(const std::string &packageId,
-                                                                                  const std::string &certsDir) noexcept :
+                                                const std::string &certsDir) noexcept :
        m_pImpl(new Impl(packageId, certsDir)) {}
 
 TrustAnchor::~TrustAnchor(void) = default;
@@ -341,11 +357,11 @@ TrustAnchor::~TrustAnchor(void) = default;
 int TrustAnchor::install(bool withSystemCerts) noexcept
 {
        if (this->m_pImpl == nullptr)
-               return -1;
+               return TRUST_ANCHOR_ERROR_OUT_OF_MEMORY;
 
        int ret = this->m_pImpl->install(withSystemCerts);
 
-       if (ret != 0) {
+       if (ret != TRUST_ANCHOR_ERROR_NONE) {
                ERROR("Failed to intall ACTA. Remove custom directory for rollback.");
                this->m_pImpl->uninstall(true);
        }
@@ -356,7 +372,7 @@ int TrustAnchor::install(bool withSystemCerts) noexcept
 int TrustAnchor::uninstall(void) noexcept
 {
        if (this->m_pImpl == nullptr)
-               return -1;
+               return TRUST_ANCHOR_ERROR_OUT_OF_MEMORY;
 
        return this->m_pImpl->uninstall();
 }
@@ -364,7 +380,7 @@ int TrustAnchor::uninstall(void) noexcept
 int TrustAnchor::launch(bool withSystemCerts) noexcept
 {
        if (this->m_pImpl == nullptr)
-               return -1;
+               return TRUST_ANCHOR_ERROR_OUT_OF_MEMORY;
 
        return this->m_pImpl->launch(withSystemCerts);
 }