Create shared directories on external storage 41/61541/37
authorArkadiusz Szulakiewicz <a.szulakiewi@partner.samsung.com>
Tue, 8 Mar 2016 14:12:49 +0000 (15:12 +0100)
committerTomasz Iwanek <t.iwanek@samsung.com>
Tue, 5 Apr 2016 07:55:17 +0000 (00:55 -0700)
Change-Id: I6cbccde9b6f18848c4a6f9bb09bbfbcfb8078412

src/common/CMakeLists.txt
src/common/security_registration.cc
src/common/security_registration.h
src/common/shared_dirs.cc [new file with mode: 0644]
src/common/shared_dirs.h [new file with mode: 0644]
src/common/step/filesystem/step_create_per_user_storage_directories.cc
src/common/step/filesystem/step_create_per_user_storage_directories.h
src/common/step/filesystem/step_create_storage_directories.cc
src/pkgdir_tool/pkgdir_tool.cc

index 09ded5c..c9450a2 100644 (file)
@@ -3,6 +3,7 @@ SET(SRCS
   app_installer.cc
   backup_paths.cc
   installer_context.cc
+  shared_dirs.cc
   plugins/plugin_factory.cc
   plugins/plugin_manager.cc
   plugins/plugin_list_parser.cc
index 94f70b8..f24bcb0 100644 (file)
@@ -17,6 +17,7 @@
 #include "common/utils/glist_range.h"
 
 namespace bf = boost::filesystem;
+namespace ci = common_installer;
 
 namespace {
 
@@ -37,7 +38,8 @@ const std::vector<std::pair<const char*,
 
 bool PrepareRequest(const std::string& app_id, const std::string& pkg_id,
     const std::string& author_id, const std::string& api_version,
-    const std::string& preload, const boost::filesystem::path& path,
+    ci::SecurityAppInstallType sec_install_type,
+    const boost::filesystem::path& path,
     uid_t uid, const std::vector<std::string>& privileges,
     app_inst_req* req, std::string* error_message) {
   if (app_id.empty() || pkg_id.empty()) {
@@ -94,14 +96,21 @@ bool PrepareRequest(const std::string& app_id, const std::string& pkg_id,
     }
   }
 
-  if (!preload.empty()) {
+  if (sec_install_type != ci::SecurityAppInstallType::None) {
     app_install_type type;
-    if (preload == "true")
-      type = SM_APP_INSTALL_PRELOADED;
-    else if (uid == GLOBAL_USER || uid == 0)
-      type = SM_APP_INSTALL_GLOBAL;
-    else
-      type = SM_APP_INSTALL_LOCAL;
+
+    switch (sec_install_type) {
+      case ci::SecurityAppInstallType::Local:
+        type = SM_APP_INSTALL_LOCAL;
+        break;
+      case ci::SecurityAppInstallType::Preload:
+        type = SM_APP_INSTALL_PRELOADED;
+        break;
+      case ci::SecurityAppInstallType::Global:
+        type = SM_APP_INSTALL_GLOBAL;
+        break;
+    }
+
     LOG(INFO) << "install_type(" << type << ")";
     error = security_manager_app_inst_req_set_install_type(req, type);
     if (error != SECURITY_MANAGER_SUCCESS) {
@@ -148,7 +157,7 @@ namespace common_installer {
 
 bool RegisterSecurityContext(const std::string& app_id,
     const std::string& pkg_id, const std::string& author_id,
-    const std::string& api_version, const std::string& preload,
+    const std::string& api_version, SecurityAppInstallType type,
     const boost::filesystem::path& path, uid_t uid,
     const std::vector<std::string>& privileges,
     std::string* error_message) {
@@ -165,7 +174,7 @@ bool RegisterSecurityContext(const std::string& app_id,
     return false;
   }
 
-  if (!PrepareRequest(app_id, pkg_id, author_id, api_version, preload, path, uid,
+  if (!PrepareRequest(app_id, pkg_id, author_id, api_version, type, path, uid,
       privileges, req, error_message)) {
     LOG(ERROR) << "Failed while preparing security_manager_app_inst_req";
     security_manager_app_inst_req_free(req);
@@ -201,8 +210,9 @@ bool UnregisterSecurityContext(const std::string& app_id,
     return false;
   }
 
-  if (!PrepareRequest(app_id, pkg_id, std::string(), std::string(), std::string(),
-      bf::path(), uid, {}, req, error_message)) {
+  if (!PrepareRequest(app_id, pkg_id, std::string(), std::string(),
+                      ci::SecurityAppInstallType::None, bf::path(), uid, {},
+                      req, error_message)) {
     LOG(ERROR) << "Failed while preparing security_manager_app_inst_req";
     security_manager_app_inst_req_free(req);
     return false;
@@ -235,8 +245,15 @@ bool RegisterSecurityContextForManifest(
     if (!app->appid) {
       return false;
     }
+    auto sec_app_type = (strcmp(manifest->preload, "true") == 0) ?
+            ci::SecurityAppInstallType::Preload :
+            ((uid == GLOBAL_USER || uid == 0) ?
+                ci::SecurityAppInstallType::Global :
+                ci::SecurityAppInstallType::Local);
+
     if (!RegisterSecurityContext(app->appid, pkg_id, cert_info->author_id.get(),
-        manifest->api_version, manifest->preload, path, uid, priv_vec, error_message)) {
+        manifest->api_version, sec_app_type, path, uid, priv_vec,
+        error_message)) {
       return false;
     }
   }
index 9949569..cdaccb7 100644 (file)
@@ -16,6 +16,8 @@
 
 namespace common_installer {
 
+enum class SecurityAppInstallType { None, Local, Global, Preload };
+
 /**
  * Adapter interface for external Security module.
  *
@@ -35,7 +37,7 @@ namespace common_installer {
  */
 bool RegisterSecurityContext(const std::string& app_id,
     const std::string& pkg_id, const std::string& author_id,
-    const std::string& api_version, const std::string& preload,
+    const std::string& api_version, SecurityAppInstallType type,
     const boost::filesystem::path& path, uid_t uid,
     const std::vector<std::string>& privileges,
     std::string* error_message);
diff --git a/src/common/shared_dirs.cc b/src/common/shared_dirs.cc
new file mode 100644 (file)
index 0000000..b5202c1
--- /dev/null
@@ -0,0 +1,537 @@
+// Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "common/shared_dirs.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/program_options.hpp>
+#include <boost/system/error_code.hpp>
+
+#include <manifest_parser/utils/logging.h>
+#include <vcore/Certificate.h>
+#include <pkgmgr-info.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <tzplatform_config.h>
+#include <sys/xattr.h>
+
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <cstdio>
+#include <exception>
+#include <iterator>
+#include <regex>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "common/security_registration.h"
+#include "common/pkgmgr_registration.h"
+#include "common/utils/base64.h"
+#include "common/utils/file_util.h"
+#include "common/utils/glist_range.h"
+
+namespace bf = boost::filesystem;
+namespace bpo = boost::program_options;
+namespace bs = boost::system;
+namespace ci = common_installer;
+
+namespace {
+
+const std::vector<const char*> kEntries = {
+  {"/"},
+  {"cache/"},
+  {"data/"},
+  {"shared/"},
+  {"shared/cache/"},
+};
+
+const char kTrustedDir[] = "shared/trusted";
+const char kSkelAppDir[] = "/etc/skel/apps_rw";
+const char kPackagePattern[] = R"(^[0-9a-zA-Z_-]+(\.?[0-9a-zA-Z_-]+)*$)";
+const char kExternalStorageDirPrefix[] = "sdcard";
+
+bool ValidateTizenPackageId(const std::string& id) {
+  std::regex package_regex(kPackagePattern);
+  return std::regex_match(id, package_regex);
+}
+
+int PkgmgrListCallback(const pkgmgrinfo_pkginfo_h handle, void *user_data) {
+  auto pkgs = reinterpret_cast<ci::PkgList*>(user_data);
+  char* pkgid = nullptr;
+  if (pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid) != PMINFO_R_OK) {
+    return -1;
+  }
+  char* api_version;
+  if (pkgmgrinfo_pkginfo_get_api_version(handle, &api_version) != PMINFO_R_OK) {
+    return -1;
+  }
+  pkgmgrinfo_certinfo_h cert_handle;
+  if (pkgmgrinfo_pkginfo_create_certinfo(&cert_handle) != PMINFO_R_OK) {
+    return -1;
+  }
+  if (pkgmgrinfo_pkginfo_load_certinfo(pkgid, cert_handle, 0) != PMINFO_R_OK) {
+    pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
+    return -1;
+  }
+  const char* author_cert;
+  if (pkgmgrinfo_pkginfo_get_cert_value(cert_handle, PMINFO_AUTHOR_SIGNER_CERT,
+      &author_cert) != PMINFO_R_OK) {
+    pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
+    return -1;
+  }
+  if (author_cert) {
+    ValidationCore::Certificate cert(author_cert,
+        ValidationCore::Certificate::FORM_BASE64);
+    unsigned char* public_key;
+    size_t len;
+    cert.getPublicKeyDER(&public_key, &len);
+    std::string author_id =
+        ci::EncodeBase64(reinterpret_cast<const char*>(public_key));
+    pkgs->emplace_back(pkgid, api_version, author_id);
+  } else {
+    pkgs->emplace_back(pkgid, std::string(), std::string());
+  }
+
+  pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
+
+  return 0;
+}
+
+ci::PkgList GetAllGlobalAppsInformation() {
+  ci::PkgList pkgs;
+  if (pkgmgrinfo_pkginfo_get_usr_list(&PkgmgrListCallback,
+      &pkgs, tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)) != PMINFO_R_OK) {
+    LOG(ERROR) << "Failed to query global application list";
+    return {};
+  }
+  return pkgs;
+}
+
+ci::PkgList GetPkgInformation(uid_t uid, const std::string& pkgid) {
+  if (!ValidateTizenPackageId(pkgid)) {
+    LOG(DEBUG) << "Package id validation failed. pkgid = " << pkgid;
+    return ci::PkgList();
+  }
+
+  ci::PkgList pkgs;
+  pkgmgrinfo_pkginfo_h handle;
+  if (pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid.c_str(), uid, &handle) !=
+      PMINFO_R_OK) {
+    LOG(DEBUG) << "pkgmgrinfo_pkginfo_get_pkginfo failed, for pkgid=" << pkgid;
+    return {};
+  }
+  if (PkgmgrListCallback(handle, &pkgs) != 0) {
+    pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+    LOG(DEBUG) << "PkgmgrListCallback failed";
+    return {};
+  }
+  pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+  return pkgs;
+}
+
+bool SetPackageDirectorySmackRules(const bf::path& base_dir,
+                                   const std::string& pkgid,
+                                   const std::string& author_id,
+                                   const std::string& api_version,
+                                   uid_t uid) {
+  if (!pkgid.empty()) {
+    std::vector<std::string> privileges;
+    std::vector<std::string> appids;
+    if (!common_installer::QueryPrivilegesForPkgId(pkgid,
+        tzplatform_getuid(TZ_SYS_GLOBALAPP_USER), &privileges)) {
+      LOG(ERROR) << "Failed to get privileges for package id";
+      return false;
+    }
+    if (!common_installer::QueryAppidsForPkgId(pkgid, &appids,
+        tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))) {
+      LOG(ERROR) << "Failed to get application ids for package id";
+      return false;
+    }
+    std::string error_message;
+    for (const auto& appid : appids) {
+      if (!common_installer::RegisterSecurityContext(appid, pkgid,
+          author_id, api_version, ci::SecurityAppInstallType::Local,
+          base_dir, uid, privileges,
+          &error_message)) {
+        LOG(ERROR) << "Failed to register security context";
+        if (!error_message.empty()) {
+          LOG(ERROR) << "error_message: " << error_message;
+        }
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool SetPackageDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
+                                            gid_t gid) {
+  bs::error_code error;
+  bf::perms perms = bf::owner_read |
+                    bf::owner_write |
+                    bf::group_read;
+  if (bf::is_directory(subpath)) {
+    perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
+  }
+  bf::permissions(subpath, perms, error);
+  if (error) {
+    LOG(ERROR) << "Failed to set permissions for: " << subpath;
+    return false;
+  }
+  int ret = chown(subpath.c_str(), uid, gid);
+  if (ret != 0) {
+    LOG(ERROR) << "Failed to change owner of: " << subpath;
+    return false;
+  }
+  return true;
+}
+
+bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
+                       const std::string& author_id,
+                       const std::string& api_version,
+                       uid_t uid, gid_t gid, const bool set_permissions) {
+  bf::path base_dir = app_dir / pkgid;
+  if (bf::exists(base_dir)) {
+    LOG(DEBUG) << "Directory for user already exist: " << base_dir;
+    return true;
+  }
+
+  bs::error_code error;
+  std::vector<const char*> dirs(kEntries);
+  if (!author_id.empty())
+    dirs.push_back(kTrustedDir);
+  for (auto& entry : dirs) {
+    bf::path subpath = base_dir / entry;
+    bf::create_directories(subpath, error);
+    if (error) {
+      LOG(ERROR) << "Failed to create directory: " << subpath;
+      return false;
+    }
+
+    if (set_permissions) {
+      if (!SetPackageDirectoryOwnerAndPermissions(subpath, uid, gid))
+        return false;
+
+      // for content
+      for (bf::recursive_directory_iterator iter(subpath);
+           iter != bf::recursive_directory_iterator(); ++iter) {
+        if (!SetPackageDirectoryOwnerAndPermissions(iter->path(), uid, gid))
+          return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bf::path GetDirectoryPathForStorage(uid_t user, std::string apps_prefix) {
+  struct passwd* pwd = getpwuid(user);  // NOLINT
+
+  bf::path apps_rw;
+  apps_rw = bf::path(apps_prefix.c_str()) / pwd->pw_name / "apps_rw";
+
+  return apps_rw;
+}
+
+bool CreateUserDirectories(uid_t user, const std::string& pkgid,
+    const std::string& author_id, const std::string& api_version,
+    const std::string& apps_prefix, const bool set_permissions) {
+
+  struct passwd* pwd = getpwuid(user);  // NOLINT
+  if (!pwd) {
+    LOG(WARNING) << "Failed to get user for home directory: " << user;
+    return false;
+  }
+
+  struct group* gr = getgrgid(pwd->pw_gid);  // NOLINT
+  if (strcmp(gr->gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
+    return false;
+
+  LOG(DEBUG) << "Creating directories for uid: " << pwd->pw_uid << ", gid: "
+             << pwd->pw_gid;
+
+  bf::path apps_rw = GetDirectoryPathForStorage(user, apps_prefix);
+  if (!CreateDirectories(apps_rw, pkgid, author_id, api_version,
+      pwd->pw_uid, pwd->pw_gid, set_permissions)) {
+    return false;
+  }
+  return true;
+}
+
+bool CreateSkelDirectories(const std::string& pkgid) {
+  bf::path path = bf::path(kSkelAppDir) / pkgid;
+  LOG(DEBUG) << "Creating directories in: " << path;
+  bs::error_code error;
+  bf::create_directories(path, error);
+
+  if (error) {
+    LOG(ERROR) << "Failed to create directory: " << path;
+    return false;
+  }
+
+  // TODO(jungh.yeon) : this is hotfix.
+  for (auto& entry : kEntries) {
+    bf::path subpath = path / entry;
+    bf::create_directories(subpath, error);
+    std::string label = "User::Pkg::" + pkgid;
+    if (error && !bf::exists(subpath)) {
+      LOG(ERROR) << "Failed to create directory: " << subpath;
+      return false;
+    }
+
+    int r =
+        lsetxattr(subpath.c_str(), "security.SMACK64TRANSMUTE", "TRUE", 4, 0);
+    if (r < 0) {
+      LOG(ERROR) << "Failed to apply transmute";
+      return false;
+    }
+
+    r = lsetxattr(subpath.c_str(), "security.SMACK64",
+                  label.c_str(), label.length(), 0);
+    if (r < 0) {
+      LOG(ERROR) << "Failed to apply label";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
+  bf::path base_dir = app_dir / pkgid;
+  bs::error_code error;
+  bf::remove_all(base_dir, error);
+  if (error) {
+    LOG(ERROR) << "Failed to delete directory: " << base_dir;
+    return false;
+  }
+  return true;
+}
+
+bool DeletePerUserDirectories(const std::string& pkgid) {
+  for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
+      iter != bf::directory_iterator();
+       ++iter) {
+    if (!bf::is_directory(iter->path()))
+      return false;
+    const bf::path& home_path = iter->path();
+    std::string user = home_path.filename().string();
+    struct passwd* pwd = getpwnam(user.c_str());  // NOLINT
+    if (!pwd) {
+      LOG(WARNING) << "Failed to get user for home directory: " << user;
+      continue;
+    }
+
+    struct group* gr = getgrgid(pwd->pw_gid);  // NOLINT
+    if (strcmp(gr->gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
+      continue;
+
+    if (ci::IsPackageInstalled(pkgid, pwd->pw_uid)) continue;
+
+    LOG(DEBUG) << "Deleting directories for uid: " << pwd->pw_uid << ", gid: "
+               << pwd->pw_gid;
+    tzplatform_set_user(pwd->pw_uid);
+    bf::path apps_rw(tzplatform_getenv(TZ_USER_APP));
+    tzplatform_reset_user();
+    if (!DeleteDirectories(apps_rw, pkgid)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool DeleteSkelDirectories(const std::string& pkgid) {
+  bf::path path = bf::path(kSkelAppDir) / pkgid;
+  LOG(DEBUG) << "Deleting directories in: " << path;
+  bs::error_code error;
+  bf::remove_all(path, error);
+  if (error) {
+    LOG(ERROR) << "Failed to delete directory: " << path;
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+namespace common_installer {
+
+bool CreateSkeletonDirectoriesForPackage(const std::string& pkgid) {
+  return CreateSkelDirectories(pkgid);
+}
+
+std::string GetDirectoryPathForInternalStorage() {
+  const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
+  if (internal_storage_prefix)
+    return std::string(internal_storage_prefix);
+  return tzplatform_getenv(TZ_SYS_HOME);
+}
+
+std::string GetDirectoryPathForExternalStorage() {
+  const char* storage_path = tzplatform_mkpath(TZ_SYS_MEDIA,
+                                               kExternalStorageDirPrefix);
+  return std::string(storage_path);
+}
+
+bool PerformInternalDirectoryCreationForUser(uid_t user,
+                                             const std::string& pkgid,
+                                             const std::string& author_id,
+                                             const std::string& api_version) {
+  const char* internal_storage_prefix = tzplatform_getenv(TZ_SYS_HOME);
+  const bool set_permissions = true;
+  if (!CreateUserDirectories(user, pkgid, author_id, api_version,
+                             internal_storage_prefix, set_permissions))
+    return false;
+  return true;
+}
+
+bool PerformExternalDirectoryCreationForUser(uid_t user,
+                                             const std::string& pkgid,
+                                             const std::string& author_id,
+                                             const std::string& api_version) {
+  const char* storage_path = tzplatform_mkpath(TZ_SYS_MEDIA,
+                                               kExternalStorageDirPrefix);
+  const bool set_permissions = false;
+  if (!bf::exists(storage_path)) {
+    LOG(WARNING) << "External storage (SD Card) is not mounted.";
+    return false;
+  }
+
+  if (CreateUserDirectories(user, pkgid, author_id, api_version,
+                            storage_path, set_permissions)) {
+  }
+  return true;
+}
+
+bool PerformInternalDirectoryCreationForAllUsers(const std::string& pkgid,
+                                                 const std::string& author_id,
+                                                 const std::string& api_ver) {
+  for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
+      iter != bf::directory_iterator();
+         ++iter) {
+    if (!bf::is_directory(iter->path()))
+        continue;
+    const bf::path& home_path = iter->path();
+    std::string user = home_path.filename().string();
+
+    struct passwd* pwd = getpwnam(user.c_str());  // NOLINT
+    if (!pwd)
+      continue;
+
+    struct group* gr = getgrgid(pwd->pw_gid);  // NOLINT
+    if (strcmp(gr->gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
+      continue;
+
+    if (!PerformInternalDirectoryCreationForUser(pwd->pw_uid,
+                                                 pkgid,
+                                                 author_id,
+                                                 api_ver))
+      LOG(ERROR) << "Could not create internal storage directories for user: "
+        << user.c_str();
+  }
+  return true;
+}
+
+bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid,
+                                                 const std::string& author_id,
+                                                 const std::string& api_ver) {
+  for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
+      iter != bf::directory_iterator();
+         ++iter) {
+
+    try {
+      if (!bf::is_directory(iter->path())) continue;
+    }
+    catch (const bf::filesystem_error&) {
+      continue;
+    }
+
+    const bf::path& home_path = iter->path();
+    std::string user = home_path.filename().string();
+
+    struct passwd* pwd = getpwnam(user.c_str());  // NOLINT
+    if (!pwd)
+      continue;
+
+    struct group* gr = getgrgid(pwd->pw_gid);  // NOLINT
+    if (strcmp(gr->gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
+      continue;
+
+    if (!PerformExternalDirectoryCreationForUser(pwd->pw_uid,
+                                                 pkgid,
+                                                 author_id,
+                                                 api_ver))
+      LOG(WARNING) << "Could not create external storage directories for user: "
+        << user.c_str();
+  }
+  return true;
+}
+
+bool SetPackageDirectorySmackRulesForUser(uid_t uid,
+                                          const std::string& pkg_path,
+                                          const std::string& pkg_id,
+                                          const std::string& author_id,
+                                          const std::string& api_version) {
+  return SetPackageDirectorySmackRules(pkg_path,
+                                       pkg_id,
+                                       author_id,
+                                       api_version,
+                                       uid);
+}
+
+
+bool SetPackageDirectorySmackRulesForAllUsers(const std::string& pkg_path,
+                                              const std::string& pkg_id,
+                                              const std::string& author_id,
+                                              const std::string& api_version) {
+  for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
+      iter != bf::directory_iterator();
+         ++iter) {
+    if (!bf::is_directory(iter->path()))
+        continue;
+    const bf::path& home_path = iter->path();
+    std::string user = home_path.filename().string();
+
+    struct passwd* pwd = getpwnam(user.c_str());  // NOLINT
+    if (!pwd) {
+      LOG(WARNING) << "Failed to get user for home directory: " << user;
+      return false;
+    }
+
+    std::string path = pkg_path + "/" + user + "apps_rw";
+
+    if (!SetPackageDirectorySmackRulesForUser(pwd->pw_uid,
+                                              path,
+                                              pkg_id,
+                                              author_id,
+                                              api_version)) {
+      LOG(WARNING) << "Failed to set directory smack rules for user: " << user;
+      continue;
+    }
+  }
+  return true;
+}
+
+
+bool PerformDirectoryDeletionForAllUsers(const std::string& pkgid) {
+  if (!DeletePerUserDirectories(pkgid))
+    return false;
+  if (!DeleteSkelDirectories(pkgid))
+    return false;
+  return true;
+}
+
+ci::PkgList CreatePkgInformationList(uid_t uid,
+                                     const std::vector<std::string>& pkgs) {
+  return pkgs.empty() ?
+      GetAllGlobalAppsInformation() : GetPkgInformation(uid, *pkgs.begin());
+}
+
+}  // namespace common_installer
diff --git a/src/common/shared_dirs.h b/src/common/shared_dirs.h
new file mode 100644 (file)
index 0000000..6cdd803
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_SHARED_DIRS_H_
+#define COMMON_SHARED_DIRS_H_
+
+#include <boost/filesystem/path.hpp>
+
+#include <string>
+#include <vector>
+
+namespace common_installer {
+
+struct PkgInfo {
+  PkgInfo(std::string pkg_id_, std::string api_version_, std::string author_)
+    : pkg_id(pkg_id_),
+      api_version(api_version_),
+      author_id(author_) {}
+
+  std::string pkg_id;
+  std::string api_version;
+  std::string author_id;
+};
+
+using PkgList = std::vector<PkgInfo>;
+
+/**
+ * \brief Performs a creation of directories for specific user in internal storage
+ *
+ * \param pkgid id of package
+ * \param author_id id of author
+ * \param api_version api version
+ * \param create_skel_directories flag
+ *
+ * \return true if succeed, false otherwise
+ *
+ */
+bool PerformInternalDirectoryCreationForUser(uid_t uid,
+                                             const std::string& pkgid,
+                                             const std::string& author_id,
+                                             const std::string& api_version);
+
+/**
+ * \brief Performs a creation of directories for specific user in external storage
+ *
+ * \param pkgid id of package
+ * \param author_id id of author
+ * \param api_version api version
+ * \param create_skel_directories flag
+ *
+ * \return true if succeed, false otherwise
+ *
+ */
+bool PerformExternalDirectoryCreationForUser(uid_t uid,
+                                             const std::string& pkgid,
+                                             const std::string& author_id,
+                                             const std::string& api_version);
+
+/**
+ * \brief Performs a creation of directories in internal storage
+ *
+ * \param pkgid id of package
+ * \param author_id id of author
+ * \param api_version api version
+ * \param create_skel_directories flag
+ *
+ * \return true if succeed, false otherwise
+ *
+ */
+bool PerformInternalDirectoryCreationForAllUsers(const std::string& pkgid,
+                                                 const std::string& author_id,
+                                                 const std::string& apiversion);
+
+/**
+ * \brief Performs a creation of directories in external storage (eg. SD card)
+ *
+ * \param pkgid id of package
+ * \param author_id id of author
+ * \param api_version api version
+ * \param create_skel_directories flag
+ *
+ * \return true if succeed, false otherwise
+ *
+ */
+bool PerformExternalDirectoryCreationForAllUsers(const std::string& pkgid,
+                                                 const std::string& author_id,
+                                                 const std::string& apiversion);
+
+/**
+ * \brief Performs deletion of directories
+ *
+ * \param pkg_path package path
+ *
+ * \return true if succeed, false otherwise
+ *
+ */
+bool PerformDirectoryDeletionForAllUsers(const std::string& pkgid);
+
+/**
+ * \brief Performs deletion of directories
+ *
+ * \param uid package path
+ * \param pkg_path package path
+ * \param pkg_id package path
+ * \param author_id package path
+ * \param api_version package path
+ *
+ *
+ * \return true if succeed, false otherwise
+ *
+ */
+bool SetPackageDirectorySmackRulesForUser(uid_t uid,
+                                          const std::string& pkg_path,
+                                          const std::string& pkg_id,
+                                          const std::string& author_id,
+                                          const std::string& api_version);
+
+/**
+ * \brief Performs deletion of directories
+ *
+ * \param pkg_path package path
+ * \param pkg_id package path
+ * \param author_id package path
+ * \param api_version package path
+ *
+ * \return true if succeed, false otherwise
+ *
+ */
+bool SetPackageDirectorySmackRulesForAllUsers(const std::string& pkg_path,
+                                              const std::string& pkg_id,
+                                              const std::string& author_id,
+                                              const std::string& api_version);
+
+/**
+ * \brief Helper function fetching information about packages
+ *
+ * \param pkgs  list of packages requested to fetch information about. If list
+ *              is empty, all possible pkg id's are considered.
+ *
+ * \return pkg_list list containing information about requested packages
+ *
+ */
+PkgList CreatePkgInformationList(uid_t uid = getuid(),
+                                 const std::vector<std::string>& pkgs =
+    std::vector<std::string>());
+
+/**
+ * \brief Returns path prefix for internal storage, typically '/home'
+ *
+ * \return path prefix
+ *
+ */
+std::string GetDirectoryPathForInternalStorage();
+
+/**
+ * \brief Returns path prefix for external storage, typically sd card mount point
+ *
+ * \return path prefix
+ *
+ */
+std::string GetDirectoryPathForExternalStorage();
+
+/**
+ * \brief Create skeleton directories for package
+ *
+ * \return bool true if succeed, false otherwise
+ *
+ */
+bool CreateSkeletonDirectoriesForPackage(const std::string& pkgid);
+
+}  // namespace common_installer
+
+#endif  // COMMON_SHARED_DIRS_H_
index 660109a..268d602 100644 (file)
@@ -3,15 +3,21 @@
 // found in the LICENSE file.
 
 #include <string>
+#include <vector>
 
 #include "common/utils/subprocess.h"
 #include "common/step/filesystem/step_create_per_user_storage_directories.h"
 
+#include "common/shared_dirs.h"
+#include "common/utils/glist_range.h"
+
 namespace common_installer {
 namespace filesystem {
 
 common_installer::Step::Status StepCreatePerUserStorageDirectories::process() {
+  if (!CreateExternalStorageDir()) return Step::Status::APP_DIR_ERROR;
   if (GLOBAL_USER != context_->uid.get()) return Step::Status::OK;
+
   std::string package_id = context_->pkgid.get();
   LOG(INFO) << "Creating per-user directories for package: " << package_id;
 
@@ -25,5 +31,52 @@ common_installer::Step::Status StepCreatePerUserStorageDirectories::process() {
   return Status::OK;
 }
 
+bool StepCreatePerUserStorageDirectories::CreateExternalStorageDir() {
+  auto manifest = context_->manifest_data.get();
+    bool has_external_storage_priv = false;
+    const char* privilege =
+        "http://tizen.org/privilege/externalstorage.appdata";
+    for (const char* priv : GListRange<char*>(manifest->privileges)) {
+      if (strcmp(priv, privilege) == 0) {
+        has_external_storage_priv = true;
+        LOG(DEBUG) << "External storage privilege has been found.";
+        break;
+      }
+    }
+    if (!has_external_storage_priv) {
+      LOG(DEBUG) << "External storage privilege not found, skipping.";
+      return true;
+    }
+    std::vector<std::string> pkg_ids = { context_->pkgid.get() };
+    auto pkg_list = CreatePkgInformationList(context_->uid.get(), pkg_ids);
+
+    if (pkg_list.empty()) {
+      LOG(ERROR) << "Could not create pkg information list.";
+      return false;
+    }
+
+    PkgInfo pkg = *pkg_list.begin();
+
+    switch (context_->request_mode.get()) {
+      case RequestMode::GLOBAL: {
+        LOG(DEBUG) << "Creating external directories for all users";
+        PerformExternalDirectoryCreationForAllUsers(pkg.pkg_id,
+                                                         pkg.author_id,
+                                                         pkg.api_version);
+      }
+      break;
+      case RequestMode::USER: {
+        LOG(DEBUG) << "Creating external directories for user: "
+            << context_->uid.get();
+        PerformExternalDirectoryCreationForUser(context_->uid.get(),
+                                                     pkg.pkg_id,
+                                                     pkg.author_id,
+                                                     pkg.api_version);
+      }
+      break;
+    }
+    return true;
+}
+
 }  // namespace filesystem
 }  // namespace common_installer
index bb1cba9..30364ee 100644 (file)
@@ -32,6 +32,9 @@ class StepCreatePerUserStorageDirectories : public common_installer::Step {
   Status precheck() override { return Status::OK; }
 
   SCOPE_LOG_TAG(CreatePerUserStorageDirectories)
+
+ private:
+  bool CreateExternalStorageDir();
 };
 
 }  // namespace filesystem
index 970d7ea..9734214 100644 (file)
@@ -8,6 +8,12 @@
 #include <boost/filesystem/path.hpp>
 #include <boost/system/error_code.hpp>
 
+#include <string>
+#include <vector>
+
+#include "common/shared_dirs.h"
+#include "common/utils/glist_range.h"
+
 namespace bf = boost::filesystem;
 namespace bs = boost::system;
 
index c4c6357..6f28ca4 100644 (file)
 #include <tzplatform_config.h>
 #include <sys/xattr.h>
 
+#include <algorithm>
 #include <cassert>
 #include <cstring>
 #include <exception>
-#include <regex>
+#include <iterator>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "common/shared_dirs.h"
 #include "common/security_registration.h"
 #include "common/pkgmgr_registration.h"
 #include "common/utils/base64.h"
@@ -38,400 +40,125 @@ namespace ci = common_installer;
 
 namespace {
 
-typedef std::vector<std::tuple<std::string, std::string, std::string>> pkg_list;
-
-const std::vector<const char*> kEntries = {
-  {"/"},
-  {"cache/"},
-  {"data/"},
-  {"shared/"},
-  {"shared/cache/"},
+enum class DirectoryOperation {
+  NONE,
+  CREATE_INTERNAL,
+  DELETE
 };
 
-const char kTrustedDir[] = "shared/trusted";
-const char kSkelAppDir[] = "/etc/skel/apps_rw";
-const char kPackagePattern[] = R"(^[0-9a-zA-Z_-]+(\.?[0-9a-zA-Z_-]+)*$)";
-
-bool ValidateTizenPackageId(const std::string& id) {
-  std::regex package_regex(kPackagePattern);
-  return std::regex_match(id, package_regex);
-}
-
-int PkgmgrListCallback(const pkgmgrinfo_pkginfo_h handle, void *user_data) {
-  auto pkgs = reinterpret_cast<pkg_list*>(user_data);
-  char* pkgid = nullptr;
-  if (pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid) != PMINFO_R_OK) {
-    return -1;
-  }
-  char* api_version;
-  if (pkgmgrinfo_pkginfo_get_api_version(handle, &api_version) != PMINFO_R_OK) {
-    return -1;
-  }
-  pkgmgrinfo_certinfo_h cert_handle;
-  if (pkgmgrinfo_pkginfo_create_certinfo(&cert_handle) != PMINFO_R_OK) {
-    return -1;
-  }
-  if (pkgmgrinfo_pkginfo_load_certinfo(pkgid, cert_handle, 0) != PMINFO_R_OK) {
-    pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
-    return -1;
-  }
-  const char* author_cert;
-  if (pkgmgrinfo_pkginfo_get_cert_value(cert_handle, PMINFO_AUTHOR_SIGNER_CERT,
-      &author_cert) != PMINFO_R_OK) {
-    pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
-    return -1;
-  }
-  if (author_cert) {
-    ValidationCore::Certificate cert(author_cert,
-        ValidationCore::Certificate::FORM_BASE64);
-    unsigned char* public_key;
-    size_t len;
-    cert.getPublicKeyDER(&public_key, &len);
-    std::string author_id =
-        ci::EncodeBase64(reinterpret_cast<const char*>(public_key));
-    pkgs->emplace_back(pkgid, author_id, api_version);
-  } else {
-    pkgs->emplace_back(pkgid, std::string(), std::string());
-  }
-
-  pkgmgrinfo_pkginfo_destroy_certinfo(cert_handle);
-
-  return 0;
-}
-
-pkg_list GetAllGlobalApps() {
-  pkg_list pkgs;
-  if (pkgmgrinfo_pkginfo_get_usr_list(&PkgmgrListCallback,
-      &pkgs, tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)) != PMINFO_R_OK) {
-    LOG(ERROR) << "Failed to query global application list";
-    return {};
-  }
-  return pkgs;
-}
-
-pkg_list GetPkg(const std::string& pkgid) {
-  pkg_list pkgs;
-  pkgmgrinfo_pkginfo_h handle;
-  if (pkgmgrinfo_pkginfo_get_pkginfo(pkgid.c_str(), &handle) != PMINFO_R_OK) {
-    return {};
-  }
-  if (PkgmgrListCallback(handle, &pkgs) != 0) {
-    pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
-    return {};
-  }
-  pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
-  return pkgs;
-}
-
-bool SetPackageDirectorySmackRules(const bf::path& base_dir,
-                                   const std::string& pkgid,
-                                   const std::string& author_id,
-                                   const std::string& api_version,
-                                   uid_t uid) {
-  if (!pkgid.empty()) {
-    std::vector<std::string> privileges;
-    std::vector<std::string> appids;
-    if (!common_installer::QueryPrivilegesForPkgId(pkgid,
-        tzplatform_getuid(TZ_SYS_GLOBALAPP_USER), &privileges)) {
-      LOG(ERROR) << "Failed to get privileges for package id";
-      return false;
-    }
-    if (!common_installer::QueryAppidsForPkgId(pkgid, &appids,
-        tzplatform_getuid(TZ_SYS_GLOBALAPP_USER))) {
-      LOG(ERROR) << "Failed to get application ids for package id";
-      return false;
-    }
-    std::string error_message;
-    for (const auto& appid : appids) {
-      if (!common_installer::RegisterSecurityContext(appid, pkgid,
-          author_id, api_version, "false", base_dir, uid, privileges,
-          &error_message)) {
-        LOG(ERROR) << "Failed to register security context";
-        if (!error_message.empty()) {
-          LOG(ERROR) << "error_message: " << error_message;
-        }
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-bool SetPackageDirectoryOwnerAndPermissions(const bf::path& subpath, uid_t uid,
-                                            gid_t gid) {
-  bs::error_code error;
-  bf::perms perms = bf::owner_read |
-                    bf::owner_write |
-                    bf::group_read;
-  if (bf::is_directory(subpath)) {
-    perms |= bf::owner_exe | bf::group_exe | bf::others_exe;
-  }
-  bf::permissions(subpath, perms, error);
-  if (error) {
-    LOG(ERROR) << "Failed to set permissions for: " << subpath;
-    return false;
-  }
-  int ret = chown(subpath.c_str(), uid, gid);
-  if (ret != 0) {
-    LOG(ERROR) << "Failed to change owner of: " << subpath;
+const char kCreateInternalMode[] = "create";
+const char kDeleteMode[] = "delete";
+const char kSinglePkgId[] = "pkgid";
+const char kAllPkgIds[] = "allglobalpkgs";
+
+template<typename ... Arguments>
+bool ExclusiveOptions(const bpo::variables_map& vm, Arguments... args) {
+  std::vector<std::string> exclusive_options {args...};
+  sort(exclusive_options.begin(), exclusive_options.end());
+  std::vector<std::string> given_options;
+  std::transform(vm.begin(), vm.end(), std::back_inserter(given_options),
+          [](const bpo::variables_map::value_type& pair) {return pair.first;});
+  sort(given_options.begin(), given_options.end());
+
+  std::vector<std::string> options_intersection;
+  std::set_intersection(exclusive_options.begin(), exclusive_options.end(),
+                        given_options.begin(), given_options.end(),
+                        back_inserter(options_intersection));
+  if (options_intersection.size() > 1) {
+    std::string exception = std::string("Exclusive options :") +
+        options_intersection[0] + " " + options_intersection[1];
+    LOG(ERROR) << exception.c_str();
     return false;
   }
   return true;
 }
 
-bool CreateDirectories(const bf::path& app_dir, const std::string& pkgid,
-                       const std::string& author_id,
-                       const std::string& api_version,
-                       uid_t uid, gid_t gid) {
-  bf::path base_dir = app_dir / pkgid;
-  if (bf::exists(base_dir)) {
-    LOG(DEBUG) << "Directory for user already exist: " << base_dir;
-    return true;
-  }
-
-  bs::error_code error;
-  std::vector<const char*> dirs(kEntries);
-  if (!author_id.empty())
-    dirs.push_back(kTrustedDir);
-  for (auto& entry : dirs) {
-    bf::path subpath = base_dir / entry;
-    bf::create_directories(subpath, error);
-    if (error) {
-      LOG(ERROR) << "Failed to create directory: " << subpath;
-      return false;
-    }
-
-    if (!SetPackageDirectoryOwnerAndPermissions(subpath, uid, gid))
-      return false;
+DirectoryOperation ParseDirectoryOptions(const bpo::variables_map& opt_map) {
+  if (opt_map.count(kCreateInternalMode))
+    return DirectoryOperation::CREATE_INTERNAL;
 
-    // for content
-    for (bf::recursive_directory_iterator iter(subpath);
-         iter != bf::recursive_directory_iterator(); ++iter) {
-      if (!SetPackageDirectoryOwnerAndPermissions(iter->path(), uid, gid))
-        return false;
-    }
-  }
-
-  if (!SetPackageDirectorySmackRules(base_dir, pkgid, author_id, api_version,
-      uid))
-    return false;
+  if (opt_map.count(kDeleteMode))
+    return DirectoryOperation::DELETE;
 
-  return true;
+  return DirectoryOperation::NONE;
 }
 
-bool CreatePerUserDirectories(const std::string& pkgid,
-    const std::string& author_id, const std::string& api_version) {
-  for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
-       iter != bf::directory_iterator(); ++iter) {
-    if (!bf::is_directory(iter->path()))
-      return false;
-    const bf::path& home_path = iter->path();
-    std::string user = home_path.filename().string();
-    char buf[1024] = {0, };
-    struct passwd pwd, *pwd_result;
-
-    int ret = getpwnam_r(user.c_str(), &pwd, buf, sizeof(buf), &pwd_result);
-    if (ret != 0 || pwd_result == NULL) {
-      LOG(WARNING) << "Failed to get user for home directory: " << user;
-      continue;
-    }
-
-    struct group gr, *gr_result;
-    ret = getgrgid_r(pwd.pw_gid, &gr, buf, sizeof(buf), &gr_result);
-    if (ret != 0 || gr_result == NULL ||
-        strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
-      continue;
-
-    LOG(DEBUG) << "Creating directories for uid: " << pwd.pw_uid << ", gid: "
-               << pwd.pw_gid << ", home: " << home_path;
-    tzplatform_set_user(pwd.pw_uid);
-    bf::path apps_rw(tzplatform_getenv(TZ_USER_APP));
-    tzplatform_reset_user();
-    if (!CreateDirectories(apps_rw, pkgid, author_id, api_version,
-        pwd.pw_uid, pwd.pw_gid)) {
-      return false;
-    }
-  }
-  return true;
+bpo::options_description CreateProgramOptions() {
+  bpo::options_description options("Allowed options");
+  options.add_options()
+      (kCreateInternalMode, "create per user diretories for global package")
+      (kDeleteMode, "delete per user diretories for global package")
+      (kAllPkgIds, "install directories for all global applications")
+      (kSinglePkgId, bpo::value<std::string>(), "package ID");
+  return options;
 }
 
-bool CreateSkelDirectories(const std::string& pkgid) {
-  bf::path path = bf::path(kSkelAppDir) / pkgid;
-  LOG(DEBUG) << "Creating directories in: " << path;
-  bs::error_code error;
-  bf::create_directories(path, error);
+ci::PkgList GetPackageListFromArgs(const bpo::variables_map& opt_map) {
+  bool allglobalpkgs = opt_map.count(kAllPkgIds) != 0;
+  if (allglobalpkgs) return ci::CreatePkgInformationList();
 
-  if (error) {
-    LOG(ERROR) << "Failed to create directory: " << path;
-    return false;
+  std::vector<std::string> pkgs;
+  if (opt_map.count(kSinglePkgId)) {
+    std::string pkgid = opt_map[kSinglePkgId].as<std::string>();
+    pkgs.push_back(std::move(pkgid));
   }
-
-  // TODO(jungh.yeon) : this is hotfix.
-  for (auto& entry : kEntries) {
-    bf::path subpath = path / entry;
-    bf::create_directories(subpath, error);
-    std::string label = "User::Pkg::" + pkgid;
-    if (error) {
-      LOG(ERROR) << "Failed to create directory: " << subpath;
-      return false;
-    }
-
-    int r =
-        lsetxattr(subpath.c_str(), "security.SMACK64TRANSMUTE", "TRUE", 4, 0);
-    if (r < 0) {
-      LOG(ERROR) << "Failed to apply transmute";
-      return false;
-    }
-
-    r = lsetxattr(subpath.c_str(), "security.SMACK64",
-                  label.c_str(), label.length(), 0);
-    if (r < 0) {
-      LOG(ERROR) << "Failed to apply label";
-      return false;
-    }
-  }
-
-  return true;
+  return ci::CreatePkgInformationList(getuid(), pkgs);
 }
 
-bool DeleteDirectories(const bf::path& app_dir, const std::string& pkgid) {
-  bf::path base_dir = app_dir / pkgid;
-  bs::error_code error;
-  bf::remove_all(base_dir, error);
-  if (error) {
-    LOG(ERROR) << "Failed to delete directory: " << base_dir;
+bool ParseCommandLine(int argc, char** argv,
+                      const bpo::options_description& options,
+                      bpo::variables_map* opt_map) {
+  bpo::store(bpo::parse_command_line(argc, argv, options), *opt_map);
+  if (!ExclusiveOptions(*opt_map, kCreateInternalMode, kDeleteMode)) {
+    LOG(ERROR) << "Could not parse arguments: incorrect directory operation";
     return false;
   }
-  return true;
-}
-
-bool DeletePerUserDirectories(const std::string& pkgid) {
-  for (bf::directory_iterator iter(tzplatform_getenv(TZ_SYS_HOME));
-       iter != bf::directory_iterator(); ++iter) {
-    if (!bf::is_directory(iter->path()))
-      return false;
-    const bf::path& home_path = iter->path();
-    std::string user = home_path.filename().string();
-    char buf[1024] = {0, };
-    struct passwd pwd, *pwd_result;
-
-    int ret = getpwnam_r(user.c_str(), &pwd, buf, sizeof(buf), &pwd_result);
-    if (ret != 0 || pwd_result == NULL) {
-      LOG(WARNING) << "Failed to get user for home directory: " << user;
-      continue;
-    }
-
-    struct group gr, *gr_result;
-
-    ret = getgrgid_r(pwd.pw_gid, &gr, buf, sizeof(buf), &gr_result);
-    if (ret != 0 || gr_result == NULL ||
-        strcmp(gr.gr_name, tzplatform_getenv(TZ_SYS_USER_GROUP)) != 0)
-      continue;
-
-    if (ci::IsPackageInstalled(pkgid, pwd.pw_uid)) continue;
-
-    LOG(DEBUG) << "Deleting directories for uid: " << pwd.pw_uid << ", gid: "
-               << pwd.pw_gid;
-    tzplatform_set_user(pwd.pw_uid);
-    bf::path apps_rw(tzplatform_getenv(TZ_USER_APP));
-    tzplatform_reset_user();
-    if (!DeleteDirectories(apps_rw, pkgid)) {
-      return false;
-    }
-  }
-  return true;
-}
 
-bool DeleteSkelDirectories(const std::string& pkgid) {
-  bf::path path = bf::path(kSkelAppDir) / pkgid;
-  LOG(DEBUG) << "Deleting directories in: " << path;
-  bs::error_code error;
-  bf::remove_all(path, error);
-  if (error) {
-    LOG(ERROR) << "Failed to delete directory: " << path;
+  if (!ExclusiveOptions(*opt_map, kSinglePkgId, kAllPkgIds)) {
+    LOG(ERROR) << "Could not parse arguments: incorrect pkgid or pkgid\'s";
     return false;
   }
+  bpo::notify(*opt_map);
   return true;
 }
 
-bool PerformDirectoryCreation(const std::string& pkgid,
-    const std::string& author_id, const std::string& api_version) {
-  if (!CreatePerUserDirectories(pkgid, author_id, api_version))
-    return false;
-  if (!CreateSkelDirectories(pkgid))
-    return false;
-  return true;
-}
-
-bool PerformDirectoryDeletion(const std::string& pkgid) {
-  if (!DeletePerUserDirectories(pkgid))
-    return false;
-  if (!DeleteSkelDirectories(pkgid))
-    return false;
-  return true;
-}
-
-void ExclusiveOptions(const bpo::variables_map& vm,
-                        const std::string& opt1, const std::string& opt2) {
-    if ((vm.count(opt1) && vm.count(opt2)) ||
-        (!vm.count(opt1) && !vm.count(opt2))) {
-        throw std::logic_error(std::string("Exclusive options '") +
-                               opt1 + "' and '" + opt2 + "'.");
-    }
-}
-
 }  // namespace
 
+
 int main(int argc, char** argv) {
-  bpo::options_description options("Allowed options");
-  options.add_options()
-      ("create", "create per user diretories for global package")
-      ("delete", "delete per user diretories for global package")
-      ("allglobalpkgs", "install directories for all global applications")
-      ("pkgid", bpo::value<std::string>(), "package ID");
+  bpo::options_description options = CreateProgramOptions();
   bpo::variables_map opt_map;
-  try {
-    bpo::store(bpo::parse_command_line(argc, argv, options), opt_map);
-    ExclusiveOptions(opt_map, "create", "delete");
-    ExclusiveOptions(opt_map, "pkgid", "allglobalpkgs");
-    bpo::notify(opt_map);
-  } catch(const std::exception& error) {
-    LOG(ERROR) << error.what();
-    return -1;
-  }
-
-  bool create_mode = opt_map.count("create") != 0;
-  bool delete_mode = opt_map.count("delete") != 0;
-  bool allglobalpkgs = opt_map.count("allglobalpkgs") != 0;
-  std::string pkgid;
-  if (opt_map.count("pkgid")) {
-    pkgid = opt_map["pkgid"].as<std::string>();
-    if (!ValidateTizenPackageId(pkgid)) {
-      LOG(ERROR) << "Pkgid is invalid";
-      return -1;
-    }
-  }
-  pkg_list pkgs;
-  if (allglobalpkgs) {
-    pkgs = GetAllGlobalApps();
-  } else {
-    pkgs = GetPkg(pkgid);
-  }
+  if (!ParseCommandLine(argc, argv, options, &opt_map)) return -1;
 
   assert(setuid(0) == 0);
 
-  if (create_mode) {
-    for (auto& p : pkgs) {
-      LOG(DEBUG) << "Running for package id: " << std::get<0>(p);
-      if (!PerformDirectoryCreation(std::get<0>(p), std::get<1>(p),
-          std::get<2>(p)))
-        continue;
-    }
-  } else if (delete_mode) {
-    for (auto& p : pkgs) {
-      LOG(DEBUG) << "Running for package id: " << std::get<0>(p);
-      if (!PerformDirectoryDeletion(std::get<0>(p)))
-        continue;
+  auto dir_operation = ParseDirectoryOptions(opt_map);
+  auto pkgs = GetPackageListFromArgs(opt_map);
+  auto create_skel_dirs = true;
+
+  for (auto& p : pkgs) {
+    switch (dir_operation) {
+      case DirectoryOperation::CREATE_INTERNAL: {
+        LOG(DEBUG) << "Running directory creation for package id: " << p.pkg_id;
+        ci::PerformInternalDirectoryCreationForAllUsers(p.pkg_id,
+                                                        p.api_version,
+                                                        p.author_id);
+        const std::string pkg_path = ci::GetDirectoryPathForInternalStorage();
+        ci::SetPackageDirectorySmackRulesForAllUsers(pkg_path,
+                                                     p.pkg_id,
+                                                     p.author_id,
+                                                     p.api_version);
+
+        ci::CreateSkeletonDirectoriesForPackage(p.pkg_id);
+      }
+      break;
+      case DirectoryOperation::DELETE: {
+        LOG(DEBUG) << "Running directory deletion for package id: " << p.pkg_id;
+        ci::PerformDirectoryDeletionForAllUsers(p.pkg_id);
+      }
+      break;
+      default:
+        break;
     }
   }
   return 0;