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
#include "common/utils/glist_range.h"
namespace bf = boost::filesystem;
+namespace ci = common_installer;
namespace {
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()) {
}
}
- 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) {
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) {
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);
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;
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;
}
}
namespace common_installer {
+enum class SecurityAppInstallType { None, Local, Global, Preload };
+
/**
* Adapter interface for external Security module.
*
*/
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);
--- /dev/null
+// 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
--- /dev/null
+// 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_
// 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;
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
Status precheck() override { return Status::OK; }
SCOPE_LOG_TAG(CreatePerUserStorageDirectories)
+
+ private:
+ bool CreateExternalStorageDir();
};
} // namespace filesystem
#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;
#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"
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;