Move pkg_initdb implementation to app-installers 04/64204/17
authorTomasz Iwanek <t.iwanek@samsung.com>
Wed, 30 Mar 2016 10:00:22 +0000 (12:00 +0200)
committerTomasz Iwanek <t.iwanek@samsung.com>
Wed, 11 May 2016 08:24:01 +0000 (10:24 +0200)
New binary name is: /usr/bin/pkg-initdb

Scripts that creates image should switch to new binary when ready
by changing called binary to given one (then old one may be removed).

/usr/bin/pkg-install-manifest will be removed in next patches.

pkg-initdb should be able to restore pkgmgr database:
 1) for user:
 $ pkg_initdb --uid 5001
 2) globaly:
 $ pkg_initdb

Requires to be submitted with:
 - https://review.tizen.org/gerrit/64351
 - https://review.tizen.org/gerrit/64204

Change-Id: If58d9326c5afcc877ac6ff3ae86924083b764f1c

13 files changed:
CMakeLists.txt
packaging/app-installers.manifest
packaging/app-installers.spec
src/CMakeLists.txt
src/common/step/configuration/step_configure.cc
src/common/step/configuration/step_parse_manifest.cc
src/common/step/security/step_check_signature.cc
src/common/step/security/step_check_signature.h
src/common/utils/subprocess.cc
src/common/utils/subprocess.h
src/pkg_initdb/CMakeLists.txt [new file with mode: 0644]
src/pkg_initdb/pkg_initdb.cc [new file with mode: 0644]
src/pkg_install_manifest/pkg_install_manifest.cc

index 8051599..f1ec0e9 100644 (file)
@@ -24,6 +24,7 @@ SET(CMAKE_CXX_FLAGS_CCOV       "-O0 -std=c++11 -g --coverage")
 # Targets
 SET(TARGET_LIBNAME_COMMON "app-installers")
 SET(TARGET_PKGDIR_TOOL "pkgdir-tool")
+SET(TARGET_PKG_INITDB "pkg_initdb")
 SET(TARGET_PKG_INSTALL_MANIFEST "pkg-install-manifest")
 
 ADD_DEFINITIONS("-Wall")
index 0502b63..db24115 100644 (file)
@@ -4,6 +4,7 @@
         </request>
         <assign>
                 <filesystem path="/usr/bin/pkgdir-tool" exec_label="User" />
+                <filesystem path="/usr/bin/pkg_initdb" exec_label="User" />
                 <filesystem path="/usr/bin/pkg-install-manifest" exec_label="User" />
         </assign>
 </manifest>
index e14e37c..8063ef4 100644 (file)
@@ -82,6 +82,7 @@ make %{?_smp_mflags}
 %attr(6750,root,root) %{_bindir}/pkgdir-tool
 %attr(6755,root,root) %{_sysconfdir}/gumd/useradd.d/20_pkgdir-tool-add.post
 %{_bindir}/pkg-install-manifest
+%{_bindir}/pkg_initdb
 %license LICENSE
 
 %files devel
index a8d55ef..ca676a1 100644 (file)
@@ -1,4 +1,5 @@
 ADD_SUBDIRECTORY(common)
+ADD_SUBDIRECTORY(pkg_initdb)
 ADD_SUBDIRECTORY(pkg_install_manifest)
 ADD_SUBDIRECTORY(pkgdir_tool)
 ADD_SUBDIRECTORY(unit_tests)
index 63d7389..5acb1fc 100644 (file)
@@ -8,7 +8,10 @@
 
 #include <pkgmgr-info.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 #include <tzplatform_config.h>
+
 #include <string>
 
 #include "common/request.h"
@@ -145,8 +148,11 @@ Step::Status StepConfigure::precheck() {
   } else {
     if (pkgmgr_->GetRequestType() == RequestType::ManifestDirectInstall ||
         pkgmgr_->GetRequestType() == RequestType::ManifestDirectUpdate) {
-      LOG(ERROR) << "Non-root user cannot request manifest direct mode.";
-      return Status::OPERATION_NOT_ALLOWED;
+      if (context_->is_preload_request.get()) {
+        LOG(ERROR) << "Direct manifest installation/update that is run from "
+                      "non-root user cannot be a preload request";
+        return Status::OPERATION_NOT_ALLOWED;
+      }
     } else if (context_->is_preload_request.get()) {
       LOG(ERROR) << "Non-root user cannot request preload request mode.";
       return Status::OPERATION_NOT_ALLOWED;
index db78f0a..84391a1 100644 (file)
@@ -665,7 +665,7 @@ bool StepParseManifest::FillSplashScreen(application_x* app,
   for (auto& splash_screen : splashscreens_info.splashscreens()) {
     splashscreen_x* splashscreen =
         static_cast<splashscreen_x*>(calloc(1, sizeof(splashscreen_x)));
-    if (context_->is_preload_request.get() == true)
+    if (context_->is_preload_request.get())
       splashscreen->src = strdup(splash_screen.src().c_str());
     else
       splashscreen->src = strdup((context_->root_application_path.get()
index 5ef7889..467ab4c 100644 (file)
@@ -5,7 +5,6 @@
 #include "common/step/security/step_check_signature.h"
 
 #include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/path.hpp>
 #include <glib.h>
 
 #include <cassert>
@@ -53,11 +52,15 @@ Step::Status StepCheckSignature::precheck() {
   return Step::Status::OK;
 }
 
+boost::filesystem::path StepCheckSignature::GetSignatureRoot() const {
+  return context_->unpacked_dir_path.get();
+}
+
 Step::Status StepCheckSignature::CheckSignatures(bool check_reference,
                                                  bool is_preload,
                                                  PrivilegeLevel* level) {
   std::string error_message;
-  if (!ValidateSignatures(context_->unpacked_dir_path.get(), level,
+  if (!ValidateSignatures(GetSignatureRoot(), level,
                          &context_->certificate_info.get(), check_reference,
                          is_preload, &error_message)) {
     on_error(Status::CERT_ERROR, error_message);
@@ -104,7 +107,7 @@ Step::Status StepCheckSignature::process() {
   PrivilegeLevel level = PrivilegeLevel::UNTRUSTED;
   bool check_reference = true;
   if (getuid() == 0 &&
-      (context_->request_type.get()== ci::RequestType::ManifestDirectInstall ||
+      (context_->request_type.get() == ci::RequestType::ManifestDirectInstall ||
       context_->request_type.get() == ci::RequestType::ManifestDirectUpdate))
     check_reference = false;
   bool is_preload = context_->is_preload_request.get();
index c4b45a6..e71671b 100644 (file)
@@ -5,6 +5,8 @@
 #ifndef COMMON_STEP_SECURITY_STEP_CHECK_SIGNATURE_H_
 #define COMMON_STEP_SECURITY_STEP_CHECK_SIGNATURE_H_
 
+#include <boost/filesystem/path.hpp>
+
 #include <manifest_parser/utils/logging.h>
 
 #include <string>
@@ -41,6 +43,9 @@ class StepCheckSignature : public Step {
    */
   Status precheck() override;
 
+ protected:
+  virtual boost::filesystem::path GetSignatureRoot() const;
+
  private:
   Status CheckSignatures(bool check_reference, bool is_preload,
                          PrivilegeLevel* level);
index a400c4c..6f4cc25 100644 (file)
@@ -17,7 +17,8 @@ namespace common_installer {
 Subprocess::Subprocess(const std::string& program)
     : program_(program),
       pid_(0),
-      started_(false) {
+      started_(false),
+      uid_(-1) {
 }
 
 bool Subprocess::RunWithArgs(const std::vector<std::string>& args) {
@@ -33,6 +34,8 @@ bool Subprocess::RunWithArgs(const std::vector<std::string>& args) {
       argv[i] = args[i - 1].c_str();
     }
     argv[args.size() + 1] = nullptr;
+    if (uid_ != -1)
+      setuid(uid_);
     execvp(argv[0], const_cast<char* const*>(argv.get()));
     LOG(ERROR) << "Failed to execv";
     return false;
index 9347c81..b03b6df 100644 (file)
@@ -23,10 +23,15 @@ class Subprocess {
       const std::vector<std::string>& args = std::vector<std::string>());
   int Wait();
 
+  void set_uid(int uid) {
+    uid_ = uid;
+  }
+
  private:
   std::string program_;
   int pid_;
   bool started_;
+  int uid_;
 };
 
 }  // namespace common_installer
diff --git a/src/pkg_initdb/CMakeLists.txt b/src/pkg_initdb/CMakeLists.txt
new file mode 100644 (file)
index 0000000..19b2b3d
--- /dev/null
@@ -0,0 +1,18 @@
+# Target - sources
+SET(SRCS
+  pkg_initdb.cc
+)
+
+# Target - definition
+ADD_EXECUTABLE(${TARGET_PKG_INITDB} ${SRCS})
+# Target - includes
+TARGET_INCLUDE_DIRECTORIES(${TARGET_PKG_INITDB} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../")
+# Target - deps
+APPLY_PKG_CONFIG(${TARGET_PKG_INITDB} PUBLIC
+  PKGMGR_DEPS
+  Boost
+)
+# Target - in-package deps
+TARGET_LINK_LIBRARIES(${TARGET_PKG_INITDB} PUBLIC ${TARGET_LIBNAME_COMMON})
+# Install
+INSTALL(TARGETS ${TARGET_PKG_INITDB} DESTINATION ${BINDIR})
diff --git a/src/pkg_initdb/pkg_initdb.cc b/src/pkg_initdb/pkg_initdb.cc
new file mode 100644 (file)
index 0000000..1f01d84
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright (c) 2015 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 <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/program_options.hpp>
+#include <boost/system/error_code.hpp>
+#include <pkgmgr_parser.h>
+#include <pkgmgr_parser_db.h>
+#include <pkgmgr-info.h>
+#include <sys/types.h>
+#include <tzplatform_config.h>
+
+#include <string>
+#include <iostream>
+
+#include "common/utils/subprocess.h"
+
+namespace bf = boost::filesystem;
+namespace bs = boost::system;
+namespace bpo = boost::program_options;
+namespace ci = common_installer;
+
+namespace {
+
+const uid_t kUserRoot = 0;
+const uid_t kGlobalUser = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
+const char kPkgInstallManifestPath[] = "/usr/bin/pkg-install-manifest";
+
+bool IsGlobal(uid_t uid) {
+  return uid == kUserRoot || uid == kGlobalUser;
+}
+
+void InitdbLoadDirectory(uid_t uid, const bf::path& directory, bool preload) {
+  std::cerr << "Loading manifest files from " << directory << std::endl;
+  for (bf::directory_iterator iter(directory); iter != bf::directory_iterator();
+       ++iter) {
+    if (!bf::is_regular_file(iter->path()))
+      continue;
+    std::cerr << "Running for: " << iter->path() << std::endl;
+    ci::Subprocess pkg_install_manifest(kPkgInstallManifestPath);
+    pkg_install_manifest.set_uid(uid);
+    if (preload)
+      pkg_install_manifest.Run("-x", iter->path().c_str(), "--preload");
+    else
+      pkg_install_manifest.Run("-x", iter->path().c_str());
+    pkg_install_manifest.Wait();
+  }
+}
+
+void RemoveOldDatabases(uid_t uid) {
+  if (!IsGlobal(uid))
+    tzplatform_set_user(uid);
+
+  bs::error_code error;
+  bf::path info_db_path(tzplatform_mkpath(
+      IsGlobal(uid) ? TZ_SYS_DB : TZ_USER_DB, ".pkgmgr_parser.db"));
+  bf::path info_db_journal_path(tzplatform_mkpath(
+      IsGlobal(uid) ? TZ_SYS_DB : TZ_USER_DB, ".pkgmgr_parser.db-journal"));
+  bf::path cert_db_path(tzplatform_mkpath(
+      IsGlobal(uid) ? TZ_SYS_DB : TZ_USER_DB, ".pkgmgr_cert.db"));
+  bf::path  cert_db_journal_path(tzplatform_mkpath(
+      IsGlobal(uid) ? TZ_SYS_DB : TZ_USER_DB, ".pkgmgr_cert.db-journal"));
+
+  bf::remove(info_db_path, error);
+  if (error)
+    std::cerr << info_db_path << " is not removed" << std::endl;
+  bf::remove(info_db_journal_path, error);
+  if (error)
+    std::cerr << info_db_journal_path << " is not removed" << std::endl;
+  bf::remove(cert_db_path, error);
+  if (error)
+    std::cerr << cert_db_path << " is not removed" << std::endl;
+  bf::remove(cert_db_journal_path, error);
+  if (error)
+    std::cerr << cert_db_journal_path << " is not removed" << std::endl;
+
+  tzplatform_reset_user();
+}
+
+}  // namespace
+
+int main(int argc, char *argv[]) {
+  if (getuid() != kUserRoot) {
+    std::cerr << "This binary should be run as root user" << std::endl;
+    return -1;
+  }
+
+  bpo::options_description options("Allowed options");
+  options.add_options()
+      ("uid,u", bpo::value<int>()->default_value(kUserRoot), "user id")
+      ("help,h", "display this help message");
+  bpo::variables_map opt_map;
+  try {
+    bpo::store(bpo::parse_command_line(argc, argv, options), opt_map);
+    if (opt_map.count("help")) {
+      std::cerr << options << std::endl;
+      return -1;
+    }
+    bpo::notify(opt_map);
+  } catch (const bpo::error& error) {
+    std::cerr << error.what() << std::endl;
+    return -1;
+  }
+  uid_t uid = opt_map["uid"].as<int>();
+
+  RemoveOldDatabases(uid);
+
+  int ret = pkgmgr_parser_create_and_initialize_db(uid);
+  if (ret < 0) {
+    std::cerr << "Cannot create db" << std::endl;
+    return -1;
+  }
+
+  if (IsGlobal(uid)) {
+    // RO location
+    bf::path ro_dir(tzplatform_getenv(TZ_SYS_RO_PACKAGES));
+    InitdbLoadDirectory(uid, ro_dir, true);
+
+    // RW location
+    bf::path rw_dir(tzplatform_getenv(TZ_SYS_RW_PACKAGES));
+    InitdbLoadDirectory(uid, rw_dir, false);
+  } else {
+    // Specified user location
+    tzplatform_set_user(uid);
+    bf::path dir(tzplatform_getenv(TZ_USER_PACKAGES));
+    InitdbLoadDirectory(uid, dir, false);
+    tzplatform_reset_user();
+  }
+
+  return ret;
+}
index c14233f..56f5bd4 100644 (file)
@@ -27,11 +27,11 @@ const char kBackendDirectoryPath[] = "/etc/package-manager/backend/";
 
 int InstallManifestOffline(const std::string& pkgid,
                            const std::string& type,
-                           const std::string& preload) {
+                           bool preload) {
   bf::path backend_path(kBackendDirectoryPath);
   backend_path /= type;
   ci::Subprocess backend(backend_path.string());
-  if (preload == "true")
+  if (preload)
     backend.Run("-y", pkgid.c_str(), "--preload");
   else
     backend.Run("-y", pkgid.c_str());
@@ -44,6 +44,7 @@ int main(int argc, char** argv) {
   bpo::options_description options("Allowed options");
   options.add_options()
       ("xml-path,x", bpo::value<std::string>()->required(), "xml package path")
+      ("preload", "run backend with preload flag")
       ("help,h", "display this help message");
   bpo::variables_map opt_map;
   try {
@@ -58,6 +59,7 @@ int main(int argc, char** argv) {
     return -1;
   }
 
+  bool preload = opt_map.count("preload") != 0;
   bf::path manifest_path(opt_map["xml-path"].as<std::string>());
   tpk::parse::TPKConfigParser parser;
   if (!parser.ParseManifest(manifest_path)) {
@@ -75,6 +77,5 @@ int main(int argc, char** argv) {
   if (type.empty())
     type = "tpk";
 
-  return InstallManifestOffline(package_info->package(), type,
-      package_info->preload());
+  return InstallManifestOffline(package_info->package(), type, preload);
 }