From: Junghoon Park Date: Fri, 6 Nov 2020 01:50:35 +0000 (+0900) Subject: Refactor pkg_upgrade tool X-Git-Tag: submit/tizen/20201123.075751~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=86d37b3d886ae2908d11e421da57b4a07466c419;p=platform%2Fcore%2Fappfw%2Fpkgmgr-tool.git Refactor pkg_upgrade tool - Redesigned - Changed language (c to c++) Change-Id: I726102f2d84ddda80046d07a40e01ba7c55dff70 Signed-off-by: Junghoon Park --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b4891e..c0181bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,13 @@ SET(CMAKE_C_FLAGS_DEBUG "-O0 -g -fPIE") SET(CMAKE_C_FLAGS_RELEASE "-O2 -fPIE") ADD_SUBDIRECTORY(src) +ADD_SUBDIRECTORY(tests) + +IF(NOT DEFINED MINIMUM_BUILD) +ENABLE_TESTING() +SET(PKGMGR_TOOL_UNIT_TESTS pkgmgr-tool_unittests) +ADD_TEST(NAME ${PKGMGR_TOOL_UNIT_TESTS} COMMAND ${PKGMGR_TOOL_UNIT_TESTS}) +ENDIF(NOT DEFINED MINIMUM_BUILD) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/mime.wac.xml DESTINATION /usr/share/mime/packages/) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/mime.tpk.xml DESTINATION /usr/share/mime/packages/) diff --git a/packaging/pkgmgr-tool.spec b/packaging/pkgmgr-tool.spec index 2de3736..a5677cf 100644 --- a/packaging/pkgmgr-tool.spec +++ b/packaging/pkgmgr-tool.spec @@ -26,26 +26,71 @@ BuildRequires: pkgconfig(pkgmgr-installer) BuildRequires: pkgconfig(aul) BuildRequires: pkgconfig(storage) BuildRequires: pkgconfig(sqlite3) +BuildRequires: pkgconfig(gmock) BuildRequires: pkgmgr-info-parser-devel BuildRequires: pkgmgr-info-parser BuildRequires: fdupes +%if 0%{?gcov:1} +BuildRequires: lcov +BuildRequires: zip +%endif Requires(posttrans): /usr/bin/pkg_initdb %description Packager Manager Tool for packaging +%package -n pkgmgr-tool_unittests +Summary: GTest for pkgmgr-tool +Group: Development/Libraries +Requires: %{name} + +%description -n pkgmgr-tool_unittests +GTest for pkgmgr-tool + +%if 0%{?gcov:1} +%package gcov +Summary: pkgmgr-tool API(gcov) +Group: System/API + +%description gcov +gcov objects of an pkgmgr-tool +%endif + %prep %setup -q cp %{SOURCE1001} . %build -%cmake . +%if 0%{?gcov:1} +export CFLAGS+=" -fprofile-arcs -ftest-coverage" +export CXXFLAGS+=" -fprofile-arcs -ftest-coverage" +export FFLAGS+=" -fprofile-arcs -ftest-coverage" +export LDFLAGS+=" -lgcov" +%endif +%cmake . %__make %{?_smp_mflags} +%if 0%{?gcov:1} +mkdir -p gcov-obj +find . -name '*.gcno' -exec cp '{}' gcov-obj ';' +%endif + +%check +ctest -V +%if 0%{?gcov:1} +lcov -c --ignore-errors graph --no-external -q -d . -o pkgmgr-tool.info +genhtml pkgmgr-tool.info -o pkgmgr-tool.out +zip -r pkgmgr-tool.zip pkgmgr-tool.out +install -m 0644 pkgmgr-tool.zip %{buildroot}%{_datadir}/gcov/pkgmgr-tool.zip +%endif %install %make_install mkdir -p %{buildroot}%{_sysconfdir}/opt/upgrade +%if 0%{?gcov:1} +mkdir -p %{buildroot}%{_datadir}/gcov/obj +install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj +%endif %fdupes %{buildroot} @@ -82,3 +127,11 @@ update-mime-database %{_datadir}/mime %attr(0700,root,root) %{_sysconfdir}/opt/upgrade/pkgmgr.patch.sh %attr(0700,root,root) /usr/share/fixed_multiuser/scripts/pkgmgr-clear-skel.sh %attr(0700,root,root) %{_sysconfdir}/package-manager/pkgmgr-label-initial-image.sh + +%files -n pkgmgr-tool_unittests +%{_bindir}/pkgmgr-tool_unittests +%{_datadir}/pkgmgr-tool_unittests/* +%if 0%{?gcov:1} +%files gcov +%{_datadir}/gcov/* +%endif diff --git a/src/install_preload_pkg/install_preload_pkg.c b/src/install_preload_pkg/install_preload_pkg.c index a99ab60..ab2396a 100644 --- a/src/install_preload_pkg/install_preload_pkg.c +++ b/src/install_preload_pkg/install_preload_pkg.c @@ -110,8 +110,8 @@ static void __make_preload_rw_list(GList *pkg_list) info = (struct pkginfo *)pkg_list->data; _D("Add [%s][%s][%s] to preload-rw list", info->pkgid, info->version, info->type); - snprintf(pkg_info, BUFSZE, "package=\"%s\"\tversion=\"%s\"\t" - "type=\"%s\":\n", + snprintf(pkg_info, BUFSZE, "\"package=%s\":\"version=%s\":" + "\"type=%s\":\"removable=true\"\n", info->pkgid, info->version, info->type); fwrite(pkg_info, 1, strlen(pkg_info), file); } diff --git a/src/pkg_upgrade/CMakeLists.txt b/src/pkg_upgrade/CMakeLists.txt old mode 100644 new mode 100755 index 6688c88..21fe1ac --- a/src/pkg_upgrade/CMakeLists.txt +++ b/src/pkg_upgrade/CMakeLists.txt @@ -1,22 +1,19 @@ # Target - sources -SET(SRCS - pkg_upgrade.c -) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SRCS) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) # Target - definition ADD_EXECUTABLE(${TARGET_PKG_UPGRADE} ${SRCS}) # Dependency APPLY_PKG_CONFIG(${TARGET_PKG_UPGRADE} PUBLIC - INIPARSER_DEPS - SQLITE_DEPS PKGMGR_INFO_DEPS - PKGMGR_DEPS PKGMGR_PARSER_DEPS - STORAGE_DEPS TZPLATFORM_DEPS SMACK_DEPS + DLOG_DEPS ) # Install -INSTALL(TARGETS ${TARGET_PKG_UPGRADE} DESTINATION bin) \ No newline at end of file +INSTALL(TARGETS ${TARGET_PKG_UPGRADE} DESTINATION bin) + diff --git a/src/pkg_upgrade/include/backend_invoker.hh b/src/pkg_upgrade/include/backend_invoker.hh new file mode 100644 index 0000000..aca83ac --- /dev/null +++ b/src/pkg_upgrade/include/backend_invoker.hh @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BACKEND_INVOKER_H_ +#define BACKEND_INVOKER_H_ + +#include +#include + +#include "common_type.hh" + +namespace common_fota { + +class BackendInvoker { + public: + BackendInvoker(std::string pkgid, PkgType type, PkgLocation loc, + PkgOperation op, bool removable); + BackendInvoker() {} + + int Run() const; + + static int XSystem(const char *argv[]); + + private: + std::list parameters_; +}; + +} // common_fota + +#endif // BACKEND_INVOKER_H_ diff --git a/src/pkg_upgrade/include/common_type.hh b/src/pkg_upgrade/include/common_type.hh new file mode 100644 index 0000000..2e657e1 --- /dev/null +++ b/src/pkg_upgrade/include/common_type.hh @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMON_TYPE_H_ +#define COMMON_TYPE_H_ + +#include +#include + +namespace common_fota { + +enum class PkgType { + TPK, + WGT, + UNKNOWN +}; + +enum class PkgLocation { + RO, + RW, + UNKNOWN +}; + +enum class PkgOperation { + INSTALL, + UPDATE, + UNINSTALL, + UNINSTALL_KEEP_RW_DATA, + COMPLEX +}; + +class PkgContext { + public: + PkgContext(std::string id, std::string version, std::string type, + bool read_only, bool removable = false) + : id_(std::move(id)), version_(std::move(version)), + type_(std::move(type)), read_only_(read_only), removable_(removable) { + if (read_only) + removable_ = false; + } + + const std::string& GetId() const { return id_; } + const std::string& GetVersion() const { return version_; } + PkgType GetType() const { + if (type_ == "wgt" ) + return PkgType::WGT; + return PkgType::TPK; + } + PkgLocation GetLocation() const { + if (read_only_) + return PkgLocation::RO; + return PkgLocation::RW; + } + bool IsReadOnly() const { return read_only_; } + bool IsRemovable() const { return removable_; } + + private: + std::string id_; + std::string version_; + std::string type_; + bool read_only_; + bool removable_; +}; + +} // common_fota + +#endif // COMMON_TYPE_H_ diff --git a/src/pkg_upgrade/include/file_logbackend.hh b/src/pkg_upgrade/include/file_logbackend.hh new file mode 100644 index 0000000..0c23b6e --- /dev/null +++ b/src/pkg_upgrade/include/file_logbackend.hh @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILE_LOGBACKEND_H_ +#define FILE_LOGBACKEND_H_ + +#include +#include +#include + +#include "logging.hh" + +namespace utils { + +class FileLogBackend : public ILogBackend { + public: + FileLogBackend(std::string file_name, int rotation_size, int max_rotation); + void WriteLog(LogLevel level, const std::string& tag, + const std::string& logstr) override; + void WriteLogToFile(); + + private: + bool Rotate(); + int GetFileSize(const std::string& file_name); + std::string GetTimeStamp(); + std::string GetPid(); + + std::string file_name_; + int rotation_size_; + int max_rotation_; + std::unique_ptr log_stream_; +}; + +} // namespace utils + +#endif // FILE_LOGBACKEND_H_ diff --git a/src/pkg_upgrade/include/logging.hh b/src/pkg_upgrade/include/logging.hh new file mode 100644 index 0000000..6ed63bc --- /dev/null +++ b/src/pkg_upgrade/include/logging.hh @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOGGING_H_ +#define LOGGING_H_ + +#include + +#ifndef PROJECT_TAG +#define PROJECT_TAG "" +#endif + +#ifdef LOG +#undef LOG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __FILENAME__ +#define __FILENAME__ \ + (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#endif + +namespace utils { + +enum class LogLevel { + LOG_ERROR, + LOG_WARNING, + LOG_INFO, + LOG_DEBUG, +}; + +log_priority LogLevelToPriority(LogLevel level); + +template struct LogTag; +template<> struct LogTag { + static constexpr const char* value = "\033[1;31m| ERROR |\033[0m"; +}; +template<> struct LogTag { + static constexpr const char* value = "\033[1;33m| WARNING |\033[0m"; +}; +template<> struct LogTag { + static constexpr const char* value = "\033[1;32m| INFO |\033[0m"; +}; +template<> struct LogTag { + static constexpr const char* value = "\033[0m| DEBUG |\033[0m"; +}; + +template > +class StringStream : private std::basic_ostringstream { + public: + using std::basic_ostringstream::str; + + template + StringStream& operator<<(const T& value) { + static_cast &>(*this) << value; + return *this; + } +}; + +// Interface class for logging backends. The custom LogBackend which wants +// log using LOG() macro should be implement following interface. +class ILogBackend { + public: + virtual void WriteLog(LogLevel level, const std::string& tag, + const std::string& logstr) = 0; +}; + +class DLogBackend : public ILogBackend { + public: + void WriteLog(LogLevel level, const std::string& tag, + const std::string& logstr) override { + dlog_print(LogLevelToPriority(level), tag.c_str(), "%s", + Escape(logstr).c_str()); + } + + private: + // Since LogCatcher passes input to dlog_print(), the input which contains + // format string(such as %d, %n) can cause unexpected result. + // This is simple function to escape '%'. + // NOTE: Is there any gorgeous way instead of this? + std::string Escape(const std::string& str) const { + std::string escaped = std::string(str); + size_t start_pos = 0; + std::string from = "%"; + std::string to = "%%"; + while ((start_pos = escaped.find(from, start_pos)) != std::string::npos) { + escaped.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + return escaped; + } +}; + +class LogCore { + public: + // Do not call this function at destructor of global object + static LogCore& GetCore() { + static LogCore core; + return core; + } + + void AddLogBackend(std::shared_ptr backend) { + backend_list_.emplace_back(backend); + } + + void Log(LogLevel level, const std::string& tag, const std::string& log) { + for (auto backend : backend_list_) + backend->WriteLog(level, tag, log); + } + + private: + LogCore() { + // add default dlog backend + AddLogBackend(std::shared_ptr(new DLogBackend())); + } + ~LogCore() = default; + LogCore(const LogCore&) = delete; + LogCore& operator=(const LogCore&) = delete; + + std::vector> backend_list_; +}; + +class LogCatcher { + public: + LogCatcher(LogLevel level, const char* tag) + : level_(level), tag_(tag) { } + + void operator&(const StringStream& str) const { + LogCore::GetCore().Log(level_, tag_, str.str()); + } + + private: + LogLevel level_; + std::string tag_; +}; + +} // namespace utils + + +inline static const constexpr char* __tag_for_logging() { + return ""; +} + +inline static const constexpr char* __tag_for_project() { + return PROJECT_TAG; +} + +// To be defined in class namespace if user want different log tag for given +// scope +#define SCOPE_LOG_TAG(TAG) \ + inline static const constexpr char* __tag_for_logging() { \ + return #TAG; \ + } \ + +// Simple logging macro of following usage: +// LOG(LEVEL) << object_1 << object_2 << object_n; +// where: +// LEVEL = ERROR | WARNING | INFO | DEBUG +#define LOG(LEVEL) \ + ::utils::LogCatcher( \ + ::utils::LogLevel::LOG_ ## LEVEL, __tag_for_project()) \ + & ::utils::StringStream() \ + << std::string(::utils::LogTag<::utils::LogLevel::LOG_ ## LEVEL>::value) \ + << " " << std::setw(25) << std::left << __tag_for_logging() \ + << " : " << std::setw(36) \ + << (std::string(__FILENAME__) + ":" + std::to_string(__LINE__)).c_str() \ + << std::setw(0) << " : " \ + +#endif // LOGGING_H_ diff --git a/src/pkg_upgrade/include/pkg_finder.hh b/src/pkg_upgrade/include/pkg_finder.hh new file mode 100644 index 0000000..5259c3b --- /dev/null +++ b/src/pkg_upgrade/include/pkg_finder.hh @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PKG_FINDER_H_ +#define PKG_FINDER_H_ + +#include +#include +#include + +#include +#include + +#include "common_type.hh" + +namespace common_fota { + +class PkgFinder { + public: + PkgFinder(); + ~PkgFinder(); + int Find(); + const std::list& GetOldPkgs() { return old_pkgs_; } + const std::list& GetNewPkgs() { return new_pkgs_; } + void SetManifestDir(std::string dir); + void SetPreloadRwListPath(std::string path); + + private: + static int PkgidListCb(const pkgmgrinfo_pkginfo_h handle, void* user_data); + int FindPreloadPkgidFromDb(bool read_only = true); + int FindPreloadPkgidFromXml(const std::string& xml_directory); + int FindPreloadPkgidFromFile(); + std::string GetValidManifest(std::string manifest); + std::string FindInfoFromXml(const std::string& manifest, + const std::string& find_info); + int MoveToChildElement(xmlTextReaderPtr reader, int depth); + void AddRwPkgInfoFromFile(const char* info_str); + std::string GetToken(const char* pBuf, const char* pKey); + void StrTrim(char *input); + int UnzipFileOnlyToPath(const char* dest_path, const char* unzip_to); + + private: + std::list old_pkgs_; + std::list new_pkgs_; + bool read_only_ = true; + std::string manifest_dir_; + std::string preload_rw_list_path_; +}; + +} // common_fota + +#endif // PKG_FINDER_H_ diff --git a/src/pkg_upgrade/include/pkg_upgrade.h b/src/pkg_upgrade/include/pkg_upgrade.h deleted file mode 100644 index de1e8de..0000000 --- a/src/pkg_upgrade/include/pkg_upgrade.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef PKG_FOTA_H_ -#define PKG_FOTA_H_ - - -#define TOKEN_TYPE_STR "type=" -#define TOKEN_PKGID_STR "package=" -#define TOKEN_VERSION_STR "version=" -#define TOKEN_OPERATION_STR "op=" -#define TOKEN_REMOVE_STR "removable=" -#define TOKEN_UPDATE_STR "update=" - -#define SEPERATOR_END '"' -#define SEPERATOR_MID ':' - - -#define ASCII(s) (const char *)s -#define XMLCHAR(s) (const xmlChar *)s - -#define BUF_SIZE 1024 -#define DIRECTORY_PERMISSION_755 0755 -#define FOTA_RESULT_FILE tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \ - "pkgmgr/fota/result.txt") - -#ifndef FREE_AND_NULL -#define FREE_AND_NULL(ptr) do { \ - if (ptr) { \ - free((void *)ptr); \ - ptr = NULL; \ - } \ -} while (0) -#endif - -#ifndef FREE_AND_STRDUP -#define FREE_AND_STRDUP(from, to) do { \ - if (to) free((void *)to); \ - if (from) to = strdup(from); \ -} while (0) -#endif - -#define _LOGE(fmt, arg...) do { \ - int fd = 0;\ - FILE* file = NULL;\ - file = fopen(FOTA_RESULT_FILE, "a");\ - if (file == NULL) break;\ - fprintf(file, "[PKG_FOTA][%5d][err] "fmt"", getpid(), ##arg); \ - fflush(file);\ - fd = fileno(file);\ - fsync(fd);\ - fclose(file);\ - fprintf(stderr, "[PKG_FOTA][%5d][err] "fmt"", getpid(), ##arg); \ -} while (0) - -#define retvm_if(expr, val, fmt, arg...) do { \ - if (expr) { \ - _LOGE("(%s)"fmt, #expr, ##arg); \ - return (val); \ - } \ -} while (0) - -#define err_if(expr, fmt, arg...) do { \ - if (expr) { \ - _LOGE("(%s)"fmt, #expr, ##arg); \ - } \ -} while (0) - -#define tryvm_if(expr, val, fmt, arg...) do { \ - if (expr) { \ - _LOGE("(%s)"fmt, #expr, ##arg); \ - val; \ - goto catch; \ - } \ -} while (0) - -typedef enum { - PKG_IS_NOT_EXIST = 0, - PKG_IS_SAME, - PKG_IS_UPDATED, - PKG_IS_INSERTED, - PKG_IS_OLD -} COMPARE_RESULT; - -typedef enum { - PKG_NEED_NOTHING = 0, - PKG_NEED_INSTALL, - PKG_NEED_UNINSTALL, - PKG_NEED_ROUPDATE, - PKG_NEED_UPDATE_TO_RW, - PKG_NEED_RWUNINSTALL, - PKG_NEED_UPDATE_TO_RO, - PKG_NEED_RO_DBREMOVE, - PKG_NEED_RO_UNINSTALL_KEEPRWDATA, - PKG_NEED_PRELOADRW_INSTALL -} UPGRADE_OPRATION; - -enum rpm_request_type { - INSTALL_REQ, - UNINSTALL_REQ, - UPGRADE_REQ -}; - -#endif /* PKG_FOTA_H_ */ diff --git a/src/pkg_upgrade/include/pkg_upgrader.hh b/src/pkg_upgrade/include/pkg_upgrader.hh new file mode 100644 index 0000000..96f446d --- /dev/null +++ b/src/pkg_upgrade/include/pkg_upgrader.hh @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PKG_UPGRADER_H_ +#define PKG_UPGRADER_H_ + +#include + +#include "backend_invoker.hh" +#include "common_type.hh" + +namespace common_fota { + +class PkgUpgrader { + public: + PkgUpgrader(const PkgContext& context, PkgOperation pkg_op); + PkgUpgrader(std::string id); + virtual ~PkgUpgrader() = default; + + PkgType GetType() const; + PkgLocation GetLocation() const; + PkgOperation GetOperation() const; + std::string GetId() const; + std::string GetVersion() const; + const BackendInvoker& GetBackendInvoker() const; + int CompareVersion(const PkgUpgrader& pkg) const; + + virtual bool Upgrade() = 0; + + private: + PkgType type_; + PkgLocation loc_; + PkgOperation op_; + std::string id_; + std::string version_; + BackendInvoker backend_; +}; + +} // namespace common_fota + +#endif // PKG_UPGRADER_H_ diff --git a/src/pkg_upgrade/include/pkg_upgrader_factory.hh b/src/pkg_upgrade/include/pkg_upgrader_factory.hh new file mode 100644 index 0000000..580a3fa --- /dev/null +++ b/src/pkg_upgrade/include/pkg_upgrader_factory.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PKG_UPGRADER_FACTORY_H_ +#define PKG_UPGRADER_FACTORY_H_ + +#include +#include +#include + +#include "pkg_finder.hh" +#include "pkg_upgrader.hh" +#include "common_type.hh" + +namespace common_fota { + +class PkgUpgraderFactory { + public: + std::list> MakeList(PkgFinder* finder); + + private: + std::list> Merge( + const std::list& old_pkgs, + const std::list& new_pkgs); + const PkgContext* FindPkgById(const std::list& pkgs, + std::string id); +}; + +} // common_fota + +#endif // PKG_UPGRADER_FACTORY_H_ diff --git a/src/pkg_upgrade/include/ro2rw_upgrader.hh b/src/pkg_upgrade/include/ro2rw_upgrader.hh new file mode 100644 index 0000000..8a30a85 --- /dev/null +++ b/src/pkg_upgrade/include/ro2rw_upgrader.hh @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RO2RW_UPGRADER_H_ +#define RO2RW_UPGRADER_H_ + +#include "pkg_upgrader.hh" + +namespace common_fota { + +class Ro2RwUpgrader : public PkgUpgrader { + public: + Ro2RwUpgrader(std::unique_ptr old_pkg, + std::unique_ptr new_pkg); + virtual ~Ro2RwUpgrader() = default; + bool Upgrade() override; + + private: + int UnzipFiles(const char* dest_path); + int UnzipXml(const std::string& pkgid); + int UnzipData(const std::string& pkgid, const std::string& dest); + int UnzipPkgFromZip(const std::string& pkgid); + + private: + std::unique_ptr old_pkg_; + std::unique_ptr new_pkg_; +}; + +} // common_fota + +#endif // RO2RW_UPGRADER_H_ diff --git a/src/pkg_upgrade/include/rw2ro_upgrader.hh b/src/pkg_upgrade/include/rw2ro_upgrader.hh new file mode 100644 index 0000000..1fb0d01 --- /dev/null +++ b/src/pkg_upgrade/include/rw2ro_upgrader.hh @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RW2RO_UPGRADER_H_ +#define RW2RO_UPGRADER_H_ + +#include "pkg_upgrader.hh" + +namespace common_fota { + +class Rw2RoUpgrader : public PkgUpgrader { + public: + Rw2RoUpgrader(std::unique_ptr old_pkg, + std::unique_ptr new_pkg); + virtual ~Rw2RoUpgrader() = default; + bool Upgrade() override; + + private: + std::unique_ptr old_pkg_; + std::unique_ptr new_pkg_; +}; + +} // common_fota + +#endif // RW2RO_UPGRADER_H_ diff --git a/src/pkg_upgrade/include/rw_upgrader.hh b/src/pkg_upgrade/include/rw_upgrader.hh new file mode 100644 index 0000000..b2a03bc --- /dev/null +++ b/src/pkg_upgrade/include/rw_upgrader.hh @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RW_UPGRADER_H_ +#define RW_UPGRADER_H_ + +#include "ro2rw_upgrader.hh" + +namespace common_fota { + +class RwUpgrader : public Ro2RwUpgrader { + public: + RwUpgrader(std::unique_ptr new_pkg) + : Ro2RwUpgrader(nullptr, std::move(new_pkg)) {} + virtual ~RwUpgrader() = default; +}; + +} // common_fota + +#endif // RW_UPGRADER_H_ diff --git a/src/pkg_upgrade/include/simple_upgrader.hh b/src/pkg_upgrade/include/simple_upgrader.hh new file mode 100644 index 0000000..0d12388 --- /dev/null +++ b/src/pkg_upgrade/include/simple_upgrader.hh @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIMPLE_UPGRADER_H_ +#define SIMPLE_UPGRADER_H_ + +#include "pkg_upgrader.hh" +#include "pkg_finder.hh" + +namespace common_fota { + +class SimpleUpgrader : public PkgUpgrader { + public: + SimpleUpgrader(const PkgContext& context, PkgOperation pkg_op); + bool Upgrade() override; +}; + +} // common_fota + +#endif // SIMPLE_UPGRADER_H_ \ No newline at end of file diff --git a/src/pkg_upgrade/include/upgrader.hh b/src/pkg_upgrade/include/upgrader.hh new file mode 100644 index 0000000..f4eeb51 --- /dev/null +++ b/src/pkg_upgrade/include/upgrader.hh @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPGRADER_H_ +#define UPGRADER_H_ + +#include +#include + +#include "file_logbackend.hh" +#include "pkg_finder.hh" +#include "pkg_upgrader.hh" + +namespace common_fota { + +class Upgrader { + public: + Upgrader(); + bool Process(PkgFinder* finder); + const std::list>& GetSuccessList() const; + const std::list>& GetFailureList() const; + void SetDbPath(const std::string& path); + + private: + int CheckAndRestoreBackupDbs(); + int CheckAndRestoreBackup(const std::string& origin_path); + int BackupDb(const std::string& src_path, const std::string& dest_path); + int MakeBackupDbs(); + void RemoveBackupPath(const std::string& origin_path); + void RemoveBackupDbs(); + int SetDbPermission(const std::string& path); + int BackupFile(const std::string& src_path, const std::string& dest_path); + int CreateBackupFlag(const std::string& path); + int CheckBackupFlag(const std::string& path); + int RemoveBackupFlag(const std::string& path); + + private: + std::shared_ptr logger_; + std::list> success_list_; + std::list> failure_list_; + std::string parser_db_; + std::string parser_db_journal_; + std::string cert_db_; + std::string cert_db_journal_; +}; + +} // common_fota + +#endif // UPGRADER_H_ diff --git a/src/pkg_upgrade/pkg_upgrade.c b/src/pkg_upgrade/pkg_upgrade.c deleted file mode 100644 index 96d628f..0000000 --- a/src/pkg_upgrade/pkg_upgrade.c +++ /dev/null @@ -1,1864 +0,0 @@ -/* - * pkg-fota - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "include/pkg_upgrade.h" - -#include - -#define USR_MANIFEST_DIRECTORY tzplatform_getenv(TZ_SYS_RO_PACKAGES) -#define OPT_USR_MANIFEST_DIRECTORY tzplatform_getenv(TZ_SYS_RW_PACKAGES) -#define RW_PKG_DIRECTORY tzplatform_getenv(TZ_SYS_RW_APP) -#define SKEL_DIRECTORY tzplatform_mkpath(TZ_SYS_ETC, "skel/apps_rw") - -#define PKGMGR_FOTA_PATH tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \ - "pkgmgr/fota") -#define PKGID_LIST_FROM_DB_FILE tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \ - "pkgmgr/fota/pkgid_list_from_db.txt") -#define PKGID_LIST_FROM_XML_FILE \ - tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \ - "pkgmgr/fota/pkgid_list_from_xml.txt") -#define PRELOAD_RW_PKG_LIST \ - tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \ - "pkgmgr/fota/.all_preload_rw_list") -#define DBPATH tzplatform_mkpath(TZ_SYS_DB, "/.pkgmgr_parser.db") -#define JOURNAL_DBPATH tzplatform_mkpath(TZ_SYS_DB, \ - "/.pkgmgr_parser.db-journal") -#define CERT_DBPATH tzplatform_mkpath(TZ_SYS_DB, "/.pkgmgr_cert.db") -#define JOURNAL_CERT_DBPATH tzplatform_mkpath(TZ_SYS_DB, \ - "/.pkgmgr_cert.db-journal") -#define OPT_ZIP_FILE "/usr/system/RestoreDir/opt.zip" -#define ALL_PRELOAD_RW_PKG_LIST "/opt/usr/share/.all_preload_rw_list" -#define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) -#define APPFW_USER "app_fw" - -struct pkginfo { - char *pkgid; - char *version; - char *type; -}; - -static char *unzip_path[BUF_SIZE] = { - "opt/usr/globalapps", - "opt/etc/skel/apps_rw", - NULL -}; - -static void __free_pkginfo(gpointer data) -{ - struct pkginfo *info = (struct pkginfo *)data; - free(info->pkgid); - free(info->version); - free(info->type); - free(info); -} - -float __get_elapsed_time() -{ - static long start_time = 0; - long endtime = 0; - struct timeval tv; - - if (start_time == 0) { - gettimeofday(&tv, NULL); - start_time = tv.tv_sec * 1000l + tv.tv_usec / 1000l; - } - - gettimeofday(&tv, NULL); - endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l; - - return (endtime - start_time)/1000.0; -} - -#define _LOG(fmt, arg...) do { \ - int fd = 0; \ - FILE *file = NULL; \ - file = fopen(FOTA_RESULT_FILE, "a"); \ - if (file == NULL) break; \ - fprintf(file, "[PKG_FOTA][%5d][%10.3fs] "fmt"", getpid(), \ - __get_elapsed_time(), ##arg); \ - fflush(file); \ - fd = fileno(file); \ - fsync(fd); \ - fclose(file); \ - fprintf(stderr, "[PKG_FOTA][%5d][%10.3fs] "fmt"", getpid(), \ - __get_elapsed_time(), ##arg); \ -} while (0) - -int remove_directory(const char *path) -{ - DIR *dir; - struct dirent *entry; - size_t path_len = strlen(path); - int ret = 0; - int iterate_ret; - char buf[BUF_SIZE] = {0}; - size_t len; - struct stat statbuf; - - dir = opendir(path); - if (!dir) - return -1; - - while (!ret && (entry = readdir(dir))) { - iterate_ret = -1; - - if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) - continue; - - len = path_len + strlen(entry->d_name) + 2; - snprintf(buf, len, "%s/%s", path, entry->d_name); - - if (!stat(buf, &statbuf)) { - if (S_ISDIR(statbuf.st_mode)) - iterate_ret = remove_directory(buf); - else - iterate_ret = unlink(buf); - } - ret = iterate_ret; - } - - closedir(dir); - if (!ret) - ret = rmdir(path); - - return ret; -} - -static void __iter_cb(gpointer key, gpointer value, gpointer user_data) -{ - - FILE *file; - char *pkgid; - char *version; - char *type; - char pkg_info[BUF_SIZE]; - pkgmgrinfo_pkginfo_h info; - - if (user_data == NULL || key == NULL) - return; - - file = user_data; - pkgid = key; - - if (pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &info)) { - _LOGE("failed to get pkginfo of %s\n", pkgid); - return; - } - - if (pkgmgrinfo_pkginfo_get_version(info, &version)) { - pkgmgrinfo_pkginfo_destroy_pkginfo(info); - return; - } - - if (pkgmgrinfo_pkginfo_get_type(info, &type)) { - pkgmgrinfo_pkginfo_destroy_pkginfo(info); - return; - } - - snprintf(pkg_info, BUF_SIZE, - "package=\"%s\"\tversion=\"%s\"\ttype=\"%s\":\n", - pkgid, version, type); - fwrite(pkg_info, 1, strlen(pkg_info), file); - pkgmgrinfo_pkginfo_destroy_pkginfo(info); -} - -static void __make_preload_rw_list(GHashTable *preload_rw_table) -{ - if (preload_rw_table == NULL) { - _LOG("preload_rw_table is null\n"); - return; - } - FILE *file = NULL; - - char buf[BUF_SIZE]; - char tmp_path[BUF_SIZE]; - snprintf(tmp_path, BUF_SIZE, "%s.tmp", ALL_PRELOAD_RW_PKG_LIST); - - if (rename(ALL_PRELOAD_RW_PKG_LIST, tmp_path)) { - if (errno != ENOENT) - _LOG("can not backup preload rw pkg list: %d", errno); - } - - file = fopen(ALL_PRELOAD_RW_PKG_LIST, "w"); - if (file == NULL) { - _LOG("can not open [%s]: %s\n", ALL_PRELOAD_RW_PKG_LIST, - strerror_r(errno, buf, sizeof(buf))); - return; - } - g_hash_table_foreach(preload_rw_table, __iter_cb, file); - fsync(fileno(file)); - fclose(file); - if (remove(tmp_path)) - _LOG("cannot remove backup file(%s): %d", tmp_path, errno); -} - -static int __is_dir(const char *dirname) -{ - struct stat stFileInfo; - - retvm_if(dirname == NULL, -1, "dirname == NULL\n"); - retvm_if(stat(dirname, &stFileInfo) < 0, -1, - "stFileInfo is not enough\n"); - - if (S_ISDIR(stFileInfo.st_mode)) - return 0; - return -1; -} - -static int __xsystem(const char *argv[]) -{ - int status = 0; - pid_t pid; - pid = fork(); - switch (pid) { - case -1: - perror("fork failed"); - return -1; - case 0: - /* child */ - execvp(argv[0], (char *const *)argv); - _exit(-1); - default: - /* parent */ - break; - } - if (waitpid(pid, &status, 0) == -1) { - perror("waitpid failed"); - return -1; - } - if (WIFSIGNALED(status)) { - perror("signal"); - return -1; - } - if (!WIFEXITED(status)) { - /* shouldn't happen */ - perror("should not happen"); - return -1; - } - return WEXITSTATUS(status); -} - -static int __check_pkgmgr_fota_dir() -{ - int ret = 0; - - if (__is_dir(PKGMGR_FOTA_PATH) < 0) { - const char *mkdir_argv[] = { "/bin/mkdir", - "-p", PKGMGR_FOTA_PATH, NULL }; - ret = __xsystem(mkdir_argv); - retvm_if(ret != 0, -1, "mkdir_argv error [%d]\n", ret); - } - - return 0; -} - -static int __remove_pkgid_list() -{ - int ret = 0; - - if (access(FOTA_RESULT_FILE, R_OK) == 0) { - ret = remove(FOTA_RESULT_FILE); - err_if(ret < 0, "remove[%s] failed", FOTA_RESULT_FILE); - } - - if (access(PKGID_LIST_FROM_DB_FILE, R_OK) == 0) { - ret = remove(PKGID_LIST_FROM_DB_FILE); - err_if(ret < 0, "remove[%s] failed", PKGID_LIST_FROM_DB_FILE); - } - - if (access(PKGID_LIST_FROM_XML_FILE, R_OK) == 0) { - ret = remove(PKGID_LIST_FROM_XML_FILE); - err_if(ret < 0, "remove[%s] failed", PKGID_LIST_FROM_XML_FILE); - } - - return 0; -} - -static int __make_pkgid_list(const char *file_path, char *pkgid, - char *version, char *type, bool is_update) -{ - FILE *fp; - - if (NULL == pkgid) - return 0; - - fp = fopen(file_path, "a+"); - if (NULL == fp) - return -1; - - fprintf(fp, "%s\"%s\" %s\"%s\" %s\"%s\" %s\"%s\":\n", - TOKEN_PKGID_STR, pkgid, - TOKEN_VERSION_STR, version, - TOKEN_TYPE_STR, type, - TOKEN_UPDATE_STR, (is_update) ? "true" : "false"); - - fclose(fp); - - return 0; -} - -static int __insert_preload_rw_table(GHashTable *preload_rw_table, - const char *pkgid, const char *version, const char *type) -{ - struct pkginfo *info; - char *package; - - info = calloc(1, sizeof(struct pkginfo)); - if (info == NULL) { - _LOGE("out of memory"); - return -1; - } - - info->pkgid = strdup(pkgid); - if (info->pkgid == NULL) { - _LOGE("out of memory"); - __free_pkginfo((struct pkginfo *)info); - return -1; - } - - info->version = strdup(version); - if (info->version == NULL) { - _LOGE("out of memory"); - __free_pkginfo((struct pkginfo *)info); - return -1; - } - - info->type = strdup(type); - if (info->type == NULL) { - _LOGE("out of memory"); - __free_pkginfo((struct pkginfo *)info); - return -1; - } - - package = strdup(pkgid); - if (package == NULL) { - _LOGE("out of memory"); - __free_pkginfo((struct pkginfo *)info); - return -1; - } - - g_hash_table_insert(preload_rw_table, package, info); - return 0; -} - -static int __delete_preload_rw_table(GHashTable *preload_rw_table, - const char *pkgid) -{ - gboolean removed; - removed = g_hash_table_remove(preload_rw_table, pkgid); - return removed ? 0 : -1; -} - -static int __pkgid_list_cb(const pkgmgrinfo_pkginfo_h handle, void *user_data) -{ - int ret = -1; - char *pkgid = NULL; - char *version = NULL; - char *type = NULL; - bool is_update = false; - - ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid); - err_if(ret < 0, "pkgmgrinfo_pkginfo_get_pkgid failed"); - - ret = pkgmgrinfo_pkginfo_get_version(handle, &version); - err_if(ret < 0, "pkgmgrinfo_pkginfo_get_version failed"); - - ret = pkgmgrinfo_pkginfo_get_type(handle, &type); - err_if(ret < 0, "pkgmgrinfo_pkginfo_get_type failed"); - - ret = pkgmgrinfo_pkginfo_is_update(handle, &is_update); - err_if(ret < 0, "pkgmgrinfo_pkginfo_is_update failed"); - - ret = __make_pkgid_list((char *)user_data, pkgid, - version, type, is_update); - return ret; -} - -static int __preload_rw_pkgid_list_cb(const pkgmgrinfo_pkginfo_h handle, - void *user_data) -{ - int ret; - char *pkgid; - char *version; - char *type; - GHashTable *preload_rw_table = (GHashTable *)user_data; - - ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid); - if (ret < 0) { - _LOGE("pkgmgrinfo_pkginfo_get_pkgid failed\n"); - return -1; - } - - ret = pkgmgrinfo_pkginfo_get_version(handle, &version); - if (ret < 0) { - _LOGE("pkgmgrinfo_pkginfo_get_version failed\n"); - return -1; - } - - ret = pkgmgrinfo_pkginfo_get_type(handle, &type); - if (ret < 0) { - _LOGE("pkgmgrinfo_pkginfo_get_type failed\n"); - return -1; - } - - ret = __insert_preload_rw_table(preload_rw_table, pkgid, version, type); - if (ret < 0) { - _LOGE("__insert_preload_rw_table failed\n"); - return -1; - } - - return 0; -} - -static void __str_trim(char *input) -{ - char *trim_str = input; - - if (input == NULL) - return; - - while (*input != 0) { - if (!isspace(*input)) { - *trim_str = *input; - trim_str++; - } - input++; - } - - *trim_str = 0; - return; -} - -static char *__getvalue(const char *pBuf, const char *pKey, int depth) -{ - const char *p = NULL; - const char *pStart = NULL; - const char *pEnd = NULL; - - p = strstr(pBuf, pKey); - if (p == NULL) - return NULL; - - pStart = p + strlen(pKey) + depth; - pEnd = strchr(pStart, SEPERATOR_END); - if (pEnd == NULL) { - pEnd = strchr(pStart, SEPERATOR_MID); - if (pEnd == NULL) - return NULL; - } - - size_t len = pEnd - pStart; - if (len <= 0) - return NULL; - - char *pRes = (char *)malloc(len + 1); - if (pRes == NULL) { - _LOG("malloc failed.\n"); - return NULL; - } - strncpy(pRes, pStart, len); - pRes[len] = 0; - - return pRes; -} - -static int __compare_pkgid(char *file_path, char *fota_pkgid, - char *fota_version, bool *is_updated) -{ - retvm_if(file_path == NULL, -1, "file_path is null.\n"); - retvm_if(fota_pkgid == NULL, -1, "fota_pkgid is null.\n"); - retvm_if(fota_version == NULL, -1, "fota_version is null.\n"); - - int ret = PKG_IS_NOT_EXIST; - FILE *fp = NULL; - char buf[BUF_SIZE] = {0}; - char *pkgid = NULL; - char *version = NULL; - char *update = NULL; - int compare = PMINFO_VERSION_SAME; - - fp = fopen(file_path, "r"); - retvm_if(fp == NULL, -1, "Fail get : %s\n", file_path); - - while (fgets(buf, BUF_SIZE, fp) != NULL) { - __str_trim(buf); - - pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1); - if (pkgid == NULL) { - _LOG("pkgid is null\n"); - continue; - } - - version = __getvalue(buf, TOKEN_VERSION_STR, 1); - if (version == NULL) { - FREE_AND_NULL(pkgid); - _LOG("compare_data is null\n"); - continue; - } - - update = __getvalue(buf, TOKEN_UPDATE_STR, 1); - if (update == NULL) { - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - _LOG("compare_data is null\n"); - continue; - } - if (!strncmp(update, "true", strlen("true"))) - *is_updated = true; - else - *is_updated = false; - - if (strcmp(pkgid, fota_pkgid) == 0) { - ret = pkgmgrinfo_compare_package_version(version, - fota_version, &compare); - if (compare == PMINFO_VERSION_NEW) { - _LOG("pkgid = %s, db version = %s, new package" - " version = %s\n", pkgid, version, - fota_version); - _LOG("pkg is updated, need to upgrade\n"); - - ret = PKG_IS_UPDATED; - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(update); - break; - } else if (compare == PMINFO_VERSION_OLD) { - ret = PKG_IS_OLD; - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(update); - break; - } - - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(update); - ret = PKG_IS_SAME; - break; - } - - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(update); - memset(buf, 0x00, BUF_SIZE); - } - - if (fp != NULL) - fclose(fp); - - return ret; -} - -static bool __check_deleted_pkg(GHashTable *preload_rw_table, - const char *fota_pkgid) -{ - if (g_hash_table_contains(preload_rw_table, fota_pkgid)) - return true; - return false; -} - -char *__manifest_to_package(const char *manifest) -{ - char *package; - - if (manifest == NULL) - return NULL; - - package = strdup(manifest); - if (package == NULL) - return NULL; - - if (!strstr(package, ".xml")) { - _LOG("%s is not a manifest file \n", manifest); - free(package); - return NULL; - } - - return package; -} - -static void __send_args_to_backend(const char *pkgid, const char *pkgtype, - int operation) -{ - int ret = 0; - - long starttime; - long endtime; - struct timeval tv; - gettimeofday(&tv, NULL); - starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l; - char *query; - char backend_cmd[BUF_SIZE]; - const char *new_pkgtype; - const char tpk_pkgtype[] = "tpk"; - - const char *preload_rw[] = { backend_cmd, "-y", pkgid, - "--preload-rw", NULL }; - const char *install_ro[] = { backend_cmd, "-y", pkgid, - "--preload", "--partial-rw", NULL }; - const char *uninstall_ro[] = { backend_cmd, "-d", pkgid, - "--preload", "--force-remove", - "--partial-rw", NULL }; - const char *uninstall_ro_keeprwdata[] = { backend_cmd, "-d", pkgid, - "--preload", "--force-remove", - "--keep-rwdata", NULL }; - const char *uninstall_ro_update[] = { backend_cmd, "-d", - pkgid, "--keep-rwdata", NULL }; - const char *db_cmd[] = {"/usr/bin/sqlite3", - NULL, NULL, NULL}; - - if (operation == PKG_NEED_NOTHING) - return; - - if (!strcmp(pkgtype, "rpm")) - new_pkgtype = tpk_pkgtype; - else - new_pkgtype = pkgtype; - - snprintf(backend_cmd, sizeof(backend_cmd), "/usr/bin/%s-backend", - new_pkgtype); - - switch (operation) { - case PKG_NEED_INSTALL: - case PKG_NEED_ROUPDATE: - ret = __xsystem(install_ro); - break; - case PKG_NEED_UNINSTALL: - ret = __xsystem(uninstall_ro); - break; - case PKG_NEED_UPDATE_TO_RW: - query = sqlite3_mprintf( - "UPDATE package_info SET " \ - "package_preload='false', " \ - "package_system='false' "\ - "WHERE package=%Q", pkgid); - db_cmd[1] = strdup(DBPATH); - db_cmd[2] = query; - ret = __xsystem(db_cmd); - FREE_AND_NULL(db_cmd[1]); - sqlite3_free(query); - break; - case PKG_NEED_RWUNINSTALL: - case PKG_NEED_UPDATE_TO_RO: - ret = __xsystem(uninstall_ro_update); - break; - case PKG_NEED_RO_DBREMOVE: - query = sqlite3_mprintf( - "PRAGMA foreign_keys=on; " \ - "DELETE FROM package_info " \ - "WHERE package=%Q", pkgid); - db_cmd[1] = strdup(DBPATH); - db_cmd[2] = query; - ret = __xsystem(db_cmd); - FREE_AND_NULL(db_cmd[1]); - sqlite3_free(query); - break; - case PKG_NEED_PRELOADRW_INSTALL: - ret = __xsystem(preload_rw); - break; - case PKG_NEED_RO_UNINSTALL_KEEPRWDATA: - ret = __xsystem(uninstall_ro_keeprwdata); - break; - } - - gettimeofday(&tv, NULL); - endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l; - - _LOG("result[%ld ms, %d] \t Pkgid[%s] \n", - (endtime - starttime), ret, pkgid); -} - -int __child_element(xmlTextReaderPtr reader, int depth) -{ - int ret = xmlTextReaderRead(reader); - int cur = xmlTextReaderDepth(reader); - while (ret == 1) { - switch (xmlTextReaderNodeType(reader)) { - case XML_READER_TYPE_ELEMENT: - if (cur == depth + 1) - return 1; - break; - case XML_READER_TYPE_TEXT: - /*text is handled by each function separately*/ - if (cur == depth + 1) - return 0; - break; - case XML_READER_TYPE_END_ELEMENT: - if (cur == depth) - return 0; - break; - default: - if (cur <= depth) - return 0; - break; - } - - ret = xmlTextReaderRead(reader); - cur = xmlTextReaderDepth(reader); - } - return ret; -} - -char *__find_info_from_xml(const char *manifest, const char *find_info) -{ - retvm_if(manifest == NULL, NULL, "manifest is null.\n"); - retvm_if(find_info == NULL, NULL, "find_info is null.\n"); - - const xmlChar *node; - xmlTextReaderPtr reader; - char *info_val = NULL; - xmlChar *tmp = NULL; - - reader = xmlReaderForFile(manifest, NULL, 0); - - if (reader) { - if (__child_element(reader, -1)) { - node = xmlTextReaderConstName(reader); - if (!node) { - printf("xmlTextReaderConstName value is NULL\n"); - goto end; - } - - if (!strcmp(ASCII(node), "manifest")) { - tmp = xmlTextReaderGetAttribute(reader, - XMLCHAR(find_info)); - if (tmp) { - FREE_AND_STRDUP(ASCII(tmp), info_val); - if (info_val == NULL) - printf("Malloc Failed\n"); - FREE_AND_NULL(tmp); - } - } else { - printf("Manifest Node is not found\n"); - } - } - } else { - printf("xmlReaderForFile value is NULL\n"); - } - -end: - if (reader) - xmlFreeTextReader(reader); - - return info_val; -} - -static int __find_preload_pkgid_from_xml(const char *file_path, - const char *xml_directory) -{ - retvm_if(file_path == NULL, -1, "file_path is NULL.\n"); - retvm_if(xml_directory == NULL, -1, "xml_directory is NULL.\n"); - - int ret = 0; - char buf[BUF_SIZE] = {0}; - DIR *dir; - struct dirent *entry = NULL; - - dir = opendir(xml_directory); - if (!dir) { - if (strerror_r(errno, buf, sizeof(buf)) == 0) - _LOG("Failed to access the [%s] because %s\n", - xml_directory, buf); - return -1; - } - - while ((entry = readdir(dir)) != NULL) { - char *manifest = NULL; - char *pkgid = NULL; - char *version = NULL; - char *type = NULL; - - if (entry->d_name[0] == '.') continue; - - manifest = __manifest_to_package(entry->d_name); - if (!manifest) { - _LOG("Failed to convert file to xml[%s]\n", - entry->d_name); - continue; - } - - snprintf(buf, sizeof(buf), "%s/%s", xml_directory, manifest); - - /*Get the package name from manifest file*/ - pkgid = __find_info_from_xml(buf, "package"); - if (pkgid == NULL) { - FREE_AND_NULL(manifest); - continue; - } - - version = __find_info_from_xml(buf, "version"); - if (version == NULL) - version = strdup("0.0.1"); - - type = __find_info_from_xml(buf, "type"); - if (type == NULL) - type = strdup("tpk"); - - ret = __make_pkgid_list((char *)file_path, pkgid, - version, type, false); - if (ret < 0) - _LOG("Make file Fail : %s => %s, %s\n", - buf, pkgid, version); - - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(manifest); - FREE_AND_NULL(type); - } - - closedir(dir); - - return 0; -} - -static int __find_preload_pkgid_from_db(const char *file_path) -{ - retvm_if(file_path == NULL, -1, "file_path is NULL.\n"); - - int ret = 0; - pkgmgrinfo_pkginfo_filter_h handle = NULL; - - ret = pkgmgrinfo_pkginfo_filter_create(&handle); - retvm_if(ret != PMINFO_R_OK, -1, - "pkginfo filter handle create failed\n"); - - ret = pkgmgrinfo_pkginfo_filter_add_bool(handle, - PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD, 1); - tryvm_if(ret < 0, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool" - "(PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD) failed\n"); - - ret = pkgmgrinfo_pkginfo_filter_add_bool(handle, - PMINFO_PKGINFO_PROP_PACKAGE_SYSTEM, 1); - tryvm_if(ret < 0, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool" - "(PMINFO_PKGINFO_PROP_PACKAGE_SYSTEM) failed\n"); - - ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(handle, - __pkgid_list_cb, (void *)file_path); - err_if(ret < 0, - "pkgmgrinfo_pkginfo_filter_foreach_pkginfo() failed\n"); - -catch: - pkgmgrinfo_pkginfo_filter_destroy(handle); - return ret; -} - -static int __find_preload_rw_pkgid_from_db(GHashTable *preload_rw_table) -{ - int ret; - pkgmgrinfo_pkginfo_filter_h handle; - - ret = pkgmgrinfo_pkginfo_filter_create(&handle); - retvm_if(ret != PMINFO_R_OK, -1, - "pkginfo filter handle create failed\n"); - - ret = pkgmgrinfo_pkginfo_filter_add_bool(handle, - PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD, 1); - tryvm_if(ret != PMINFO_R_OK, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool" - "(PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD) failed\n"); - - ret = pkgmgrinfo_pkginfo_filter_add_bool(handle, - PMINFO_PKGINFO_PROP_PACKAGE_REMOVABLE, 1); - tryvm_if(ret != PMINFO_R_OK, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool" - "(PMINFO_PKGINFO_PROP_PACKAGE_REMOVABLE) failed\n"); - - ret = pkgmgrinfo_pkginfo_filter_add_bool(handle, - PMINFO_PKGINFO_PROP_PACKAGE_READONLY, 0); - tryvm_if(ret != PMINFO_R_OK, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool" - "(PMINFO_PKGINFO_PROP_PACKAGE_READONLY) failed\n"); - - ret = pkgmgrinfo_pkginfo_filter_add_bool(handle, - PMINFO_PKGINFO_PROP_PACKAGE_SYSTEM, 0); - tryvm_if(ret != PMINFO_R_OK, ret = -1, "pkgmgrinfo_pkginfo_filter_add_bool" - "(PMINFO_PKGINFO_PROP_PACKAGE_SYSTEM) failed\n"); - - ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(handle, - __preload_rw_pkgid_list_cb, (void *)preload_rw_table); - err_if(ret != PMINFO_R_OK, - "pkgmgrinfo_pkginfo_filter_foreach_pkginfo() failed\n"); - - ret = 0; -catch: - pkgmgrinfo_pkginfo_filter_destroy(handle); - return ret; -} - -static int __find_matched_pkgid_from_list(const char *source_file, - const char *target_file) -{ - retvm_if(source_file == NULL, -1, "source_file is NULL.\n"); - retvm_if(target_file == NULL, -1, "target_file is NULL.\n"); - - FILE *fp = NULL; - char buf[BUF_SIZE] = {0}; - char *pkgid = NULL; - char *version = NULL; - char *pkgtype = NULL; - - int same_pkg_cnt = 0; - int update_pkg_cnt = 0; - int insert_pkg_cnt = 0; - int total_pkg_cnt = 0; - - int compare_result = 0; - int operation; - - bool db_update; - - fp = fopen(source_file, "r"); - retvm_if(fp == NULL, -1, "Fail get : %s\n", source_file); - - _LOG("Searching...... inserted or Updated package \n"); - - while (fgets(buf, BUF_SIZE, fp) != NULL) { - __str_trim(buf); - - pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1); - if (pkgid == NULL) - continue; - - version = __getvalue(buf, TOKEN_VERSION_STR, 1); - if (version == NULL) { - free(pkgid); - continue; - } - pkgtype = __getvalue(buf, TOKEN_TYPE_STR, 1); - if (pkgtype == NULL) { - free(version); - free(pkgid); - continue; - } - - operation = PKG_NEED_NOTHING; - compare_result = __compare_pkgid((char *)target_file, pkgid, - version, &db_update); - if (compare_result == PKG_IS_NOT_EXIST) { - _LOG("pkgid[%s] is installed, Start install\n", pkgid); - operation = PKG_NEED_INSTALL; - insert_pkg_cnt++; - } else if (compare_result == PKG_IS_SAME) { - if (db_update) { - operation = PKG_NEED_RWUNINSTALL; - update_pkg_cnt++; - } else { - operation = PKG_NEED_NOTHING; - same_pkg_cnt++; - } - } else if (compare_result == PKG_IS_UPDATED) { - if (db_update) { - operation = PKG_NEED_UPDATE_TO_RO; - } else { - operation = PKG_NEED_ROUPDATE; - } - update_pkg_cnt++; - } - - total_pkg_cnt++; - __send_args_to_backend(pkgid, pkgtype, operation); - - memset(buf, 0x00, BUF_SIZE); - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(pkgtype); - } - - _LOG("-------------------------------------------------------\n"); - _LOG("[Total pkg=%d, same pkg=%d, updated pkg=%d, " - "inserted package=%d]\n", - total_pkg_cnt, same_pkg_cnt, update_pkg_cnt, insert_pkg_cnt); - _LOG("-------------------------------------------------------\n"); - - if (fp != NULL) - fclose(fp); - - return 0; -} - -static bool __find_pkgid_from_rw_list(const char *pkgid) -{ - if (pkgid == NULL) - return false; - - bool ret = false; - FILE *fp = NULL; - char buf[BUF_SIZE] = {0}; - char *preload_rw_pkgid = NULL; - - fp = fopen(PRELOAD_RW_PKG_LIST, "r"); - retvm_if(fp == NULL, -1, "Failed to open : %s\n", PRELOAD_RW_PKG_LIST); - - while (fgets(buf, BUF_SIZE, fp) != NULL) { - __str_trim(buf); - - preload_rw_pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1); - if (preload_rw_pkgid == NULL) { - _LOG("Failed to get pkgidstring[%s]\n", buf); - continue; - } - - if (strcmp(pkgid, preload_rw_pkgid) == 0) { - _LOG("pkgid[%s] is converted to preload rw pkg\n", pkgid); - FREE_AND_NULL(preload_rw_pkgid); - ret = true; - break; - } - FREE_AND_NULL(preload_rw_pkgid); - } - - fclose(fp); - return ret; -} - -static int __unzip_file_only_to_path(char *dest_path, char *unzip_to) -{ - const char *unzip_argv[] = { "/usr/bin/unzip", "-joXqq", - OPT_ZIP_FILE, dest_path, "-d", unzip_to, NULL }; - int ret = __xsystem(unzip_argv); - - return ret; -} - -static int __unzip_files(char *dest_path) -{ - const char *unzip_argv[] = { "/usr/bin/unzip", "-oXqq", - OPT_ZIP_FILE, dest_path, "-d", "/", NULL }; - int ret = __xsystem(unzip_argv); - - return ret; -} - -static int __install_preload_rw(const char *pkgid, const char *version, - const char *pkgtype, GHashTable *preload_rw_table) -{ - if (pkgid == NULL || version == NULL || pkgtype == NULL) - return -1; - - int index; - int ret; - char buf[BUF_SIZE] = {0}; - - /* copy modified manifest */ - snprintf(buf, BUF_SIZE, "%s/%s.xml", - (tzplatform_getenv(TZ_SYS_RW_PACKAGES) + 1), pkgid); - ret = __unzip_files(buf); - if (ret != 0) { - _LOG("Failed to unzip file from backup[%s]\n", buf); - return ret; - } - - /* copy stored signature */ - snprintf(buf, BUF_SIZE, "%s/signatures/%s.txt", - (tzplatform_getenv(TZ_SYS_SHARE) + 1), pkgid); - ret = __unzip_files(buf); - if (ret != 0) { - _LOG("Failed to unzip file from backup[%s]\n", buf); - return ret; - } - - /* copy RO and RW components */ - for (index = 0; index < BUF_SIZE; index++) { - if (unzip_path[index] == NULL) - break; - - snprintf(buf, BUF_SIZE, "%s/%s/*", unzip_path[index], pkgid); - ret = __unzip_files(buf); - if (ret != 0) { - _LOG("Failed to unzip file from backup[%s]\n", buf); - return ret; - } - } - - ret = __insert_preload_rw_table(preload_rw_table, pkgid, version, - pkgtype); - retvm_if(ret < 0, -1, "__insert_preload_rw_table fail\n"); - - __send_args_to_backend(pkgid, pkgtype, PKG_NEED_PRELOADRW_INSTALL); - return ret; -} - -static void __convert_preload_to_rw(const char *pkgid, const char *version, - const char *pkgtype, GHashTable *preload_rw_table) -{ - if (pkgid == NULL || version == NULL || pkgtype == NULL) - return; - char buf[BUF_SIZE] = {0}; - int ret; - - snprintf(buf, BUF_SIZE, "%s/skel/apps_rw/%s", - tzplatform_getenv(TZ_SYS_ETC), pkgid); - - __send_args_to_backend(pkgid, pkgtype, PKG_NEED_RO_UNINSTALL_KEEPRWDATA); - ret = remove_directory(buf); - if (ret != 0) - _LOG("Failed to remove directory[%s]\n", buf); - - ret = __install_preload_rw(pkgid, version, pkgtype, preload_rw_table); - if (ret != 0) { - _LOG("Failed install preload rw pkg[%s]\n", pkgid); - return; - } -} - -static int __find_deleted_pkgid_from_list(const char *source_file, - const char *target_file, GHashTable *preload_rw_table) -{ - retvm_if(source_file == NULL, -1, "source_file is NULL.\n"); - retvm_if(target_file == NULL, -1, "target_file is NULL.\n"); - - FILE *fp = NULL; - char buf[BUF_SIZE] = {0}; - char *pkgid; - char *version; - char *pkgtype = NULL; - char *update = NULL; - bool is_preload_rw_pkg; - bool xml_update; - int deleted_pkg_cnt = 0; - int modified_pkg_cnt = 0; - int total_pkg_cnt = 0; - int compare_result = 0; - - fp = fopen(source_file, "r"); - retvm_if(fp == NULL, -1, "Fail get : %s\n", source_file); - - _LOG("Searching...... deleted package \n"); - - while (fgets(buf, BUF_SIZE, fp) != NULL) { - __str_trim(buf); - - pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1); - version = __getvalue(buf, TOKEN_VERSION_STR, 1); - pkgtype = __getvalue(buf, TOKEN_TYPE_STR, 1); - if (pkgid == NULL || version == NULL || pkgtype == NULL) { - _LOG("Failed to get pkg info from string[%s]\n", buf); - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(pkgtype); - continue; - } - - compare_result = __compare_pkgid((char *)target_file, pkgid, - version, &xml_update); - if (compare_result == PKG_IS_NOT_EXIST) { - update = __getvalue(buf, TOKEN_UPDATE_STR, 1); - if (update == NULL) { - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(pkgtype); - continue; - } - - is_preload_rw_pkg = __find_pkgid_from_rw_list(pkgid); - - if (!strncmp(update, "false", strlen("false"))) { - if (is_preload_rw_pkg) { - __convert_preload_to_rw(pkgid, version, - pkgtype, - preload_rw_table); - modified_pkg_cnt++; - } else { - __send_args_to_backend(pkgid, pkgtype, - PKG_NEED_UNINSTALL); - deleted_pkg_cnt++; - } - } else { - __send_args_to_backend(pkgid, pkgtype, - PKG_NEED_UPDATE_TO_RW); - modified_pkg_cnt++; - if (is_preload_rw_pkg) { - __send_args_to_backend(pkgid, pkgtype, - PKG_NEED_RWUNINSTALL); - __install_preload_rw(pkgid, version, - pkgtype, - preload_rw_table); - } - } - } - total_pkg_cnt++; - - memset(buf, 0x00, BUF_SIZE); - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(pkgtype); - FREE_AND_NULL(update); - } - - _LOG("-------------------------------------------------------\n"); - _LOG("[Total pkg=%d, deleted package=%d, modified package=%d]\n", - total_pkg_cnt, deleted_pkg_cnt, modified_pkg_cnt); - _LOG("-------------------------------------------------------\n"); - - if (fp != NULL) - fclose(fp); - - return 0; - -} - -static int __get_pkgid_list_from_db_and_xml() -{ - _LOG("=======================================================\n"); - _LOG("RO preload package fota\n"); - _LOG("=======================================================\n"); - - int ret = 0; - char updated_preload_rw_list[BUF_SIZE]; - - /*get pkg info on pkgmgr db, it means old version */ - ret = __find_preload_pkgid_from_db(PKGID_LIST_FROM_DB_FILE); - retvm_if(ret < 0, -1, "__find_preload_pkgid_from_db fail.\n"); - - _LOG("Make pkgid list from db success!! \n"); - - /*get pkg info on xml, it means new version */ - ret = __find_preload_pkgid_from_xml(PKGID_LIST_FROM_XML_FILE, - USR_MANIFEST_DIRECTORY); - retvm_if(ret < 0, -1, "__find_preload_pkgid_from_xml fail.\n"); - - _LOG("Make pkgid list from xml success!! \n"); - - - /*get preload rw pkg info on xml from opt.zip, it means new version */ - snprintf(updated_preload_rw_list, sizeof(updated_preload_rw_list), "%s", - ALL_PRELOAD_RW_PKG_LIST); - ret = __unzip_file_only_to_path(updated_preload_rw_list + 1, - (char *)PKGMGR_FOTA_PATH); - if (ret != 0) { - _LOG("Failed to unzip file from backup[%s]\n", - updated_preload_rw_list); - return ret; - } - - _LOG("Make rw pkgid list from xml success!! \n"); - - return 0; -} - -static int __process_ro_fota(GHashTable *preload_rw_table) -{ - int ret; - long starttime; - long endtime; - struct timeval tv; - - xmlInitParser(); - - gettimeofday(&tv, NULL); - starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l; - - /* find deleted pkgid */ - ret = __find_deleted_pkgid_from_list(PKGID_LIST_FROM_DB_FILE, - PKGID_LIST_FROM_XML_FILE, preload_rw_table); - err_if(ret < 0, "__find_deleted_pkgid_from_list fail.\n"); - - /* find updated, inserted pkgid */ - ret = __find_matched_pkgid_from_list(PKGID_LIST_FROM_XML_FILE, - PKGID_LIST_FROM_DB_FILE); - err_if(ret < 0, "__find_matched_pkgid_from_list fail.\n"); - - gettimeofday(&tv, NULL); - endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l; - - _LOG("=======================================================\n"); - _LOG("End RO process[time : %ld ms]\n", endtime - starttime); - _LOG("=======================================================\n"); - - xmlCleanupParser(); - - return 0; -} - -static void __remove_pkg_directories(const char *pkgid) -{ - int i; - int ret; - char buf[BUF_SIZE]; - const char *base_dirs[] = { - OPT_USR_MANIFEST_DIRECTORY, - RW_PKG_DIRECTORY, - SKEL_DIRECTORY, - NULL - }; - - for (i = 0; base_dirs[i] != NULL; i++) { - ret = snprintf(buf, sizeof(buf), "%s/%s", base_dirs[i], pkgid); - if (ret < 0 || ret > sizeof(buf)) { - printf("snprintf fail\n"); - continue; - } - if (!access(buf, F_OK)) { - if (remove_directory(buf)) - _LOGE("failed to remove directory: %s", buf); - } - } -} - -static int __process_rw_fota(GHashTable *preload_rw_table) -{ - FILE *fp = NULL; - char buf[BUF_SIZE] = {0}; - int ret = -1; - char *pkgid = NULL; - char *list_version = NULL; - char *db_stored_version = NULL; - char *pkgtype = NULL; - char *version = NULL; - pkgmgrinfo_pkginfo_h handle = NULL; - int compare = PMINFO_VERSION_SAME; - long total_time = 0; - - long starttime; - long endtime; - struct timeval tv; - bool is_deleted_pkg; - - _LOG("=======================================================\n"); - _LOG("RW preload package fota\n"); - _LOG("=======================================================\n"); - - fp = fopen(PRELOAD_RW_PKG_LIST, "r"); - retvm_if(fp == NULL, -1, "Fail get : %s\n", PRELOAD_RW_PKG_LIST); - - while (fgets(buf, BUF_SIZE, fp) != NULL) { - __str_trim(buf); - - gettimeofday(&tv, NULL); - starttime = tv.tv_sec * 1000l + tv.tv_usec / 1000l; - - pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1); - if (pkgid == NULL) - continue; - - ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &handle); - if (ret == PMINFO_R_OK) { - list_version = __getvalue(buf, TOKEN_VERSION_STR, 1); - if (list_version == NULL) { - FREE_AND_NULL(pkgid); - continue; - } - ret = pkgmgrinfo_pkginfo_get_version(handle, &db_stored_version); - ret = pkgmgrinfo_compare_package_version(db_stored_version, - list_version, &compare); - if (ret != PMINFO_R_OK) { - _LOG("can not compare pkg version[%s]\n", pkgid); - pkgmgrinfo_pkginfo_destroy_pkginfo(handle); - handle = NULL; - FREE_AND_NULL(pkgid); - FREE_AND_NULL(list_version); - continue; - } - - if (compare != PMINFO_VERSION_NEW) { - /* package version is not update on FOTA. */ - _LOG("pkgid[%s] is not updated\n", pkgid); - pkgmgrinfo_pkginfo_destroy_pkginfo(handle); - handle = NULL; - FREE_AND_NULL(pkgid); - FREE_AND_NULL(list_version); - continue; - } - - _LOG("pkgid[%s] is updated, need to upgrade " - "from version [%s] to [%s]\n", - pkgid, db_stored_version, list_version); - } else { - is_deleted_pkg = __check_deleted_pkg(preload_rw_table, pkgid); - if (is_deleted_pkg) { - _LOG("pkgid[%s] is deleted pkg\n", pkgid); - __delete_preload_rw_table(preload_rw_table, - pkgid); - /* maybe there are pkg directories which are - * extracted from opt.zip by FOTA - */ - __remove_pkg_directories(pkgid); - FREE_AND_NULL(pkgid); - continue; - } - _LOG("pkgid[%s] is new\n", pkgid); - } - - version = __getvalue(buf, TOKEN_VERSION_STR, 1); - pkgtype = __getvalue(buf, TOKEN_TYPE_STR, 1); - __install_preload_rw(pkgid, version, pkgtype, preload_rw_table); - - FREE_AND_NULL(pkgid); - FREE_AND_NULL(pkgtype); - FREE_AND_NULL(version); - - if (handle) - pkgmgrinfo_pkginfo_destroy_pkginfo(handle); - - gettimeofday(&tv, NULL); - endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l; - total_time += (int)(endtime - starttime); - _LOG("finish request [time : %d ms]\n", - (int)(endtime - starttime)); - } - fclose(fp); - - return 0; -} - -static int __check_tmp_all_preload_rw_pkg_list() -{ - char buf[BUF_SIZE]; - char tmp_path[BUF_SIZE]; - snprintf(tmp_path, BUF_SIZE, "%s.tmp", ALL_PRELOAD_RW_PKG_LIST); - if (access(tmp_path, F_OK) == 0) { - if (rename(tmp_path, ALL_PRELOAD_RW_PKG_LIST)) { - _LOG("rename tmp all preload rw pkg list fail : %s\n", - strerror_r(errno, buf, sizeof(buf))); - return -1; - } - } - return 0; -} - -static int __fill_preload_rw_table(GHashTable *preload_rw_table) -{ - FILE *fp; - char buf[BUF_SIZE]; - char *pkgid; - char *version; - char *type; - - fp = fopen(ALL_PRELOAD_RW_PKG_LIST, "r"); - retvm_if(fp == NULL, -1, "Fail get : %s\n", ALL_PRELOAD_RW_PKG_LIST); - - while (fgets(buf, BUF_SIZE, fp) != NULL) { - __str_trim(buf); - - pkgid = __getvalue(buf, TOKEN_PKGID_STR, 1); - if (pkgid == NULL) { - _LOG("pkgid is null\n"); - continue; - } - - version = __getvalue(buf, TOKEN_VERSION_STR, 1); - if (version == NULL) { - _LOG("version is null\n"); - version = strdup(""); - if (version == NULL) { - _LOGE("out of memory\n"); - FREE_AND_NULL(pkgid); - continue; - } - } - - type = __getvalue(buf, TOKEN_TYPE_STR, 1); - if (type == NULL) { - _LOG("type is null\n"); - type = strdup(""); - if (type == NULL) { - _LOGE("out of memory\n"); - FREE_AND_NULL(version); - FREE_AND_NULL(pkgid); - continue; - } - } - - __insert_preload_rw_table(preload_rw_table, pkgid, version, - type); - FREE_AND_NULL(pkgid); - FREE_AND_NULL(version); - FREE_AND_NULL(type); - } - fclose(fp); - - return 0; -} - -#define DB_LABEL "User::Home" -#define SET_SMACK_LABEL(x) \ -do { \ - if (smack_setlabel((x), DB_LABEL, SMACK_LABEL_ACCESS)) \ - _LOGE("failed chsmack -a %s %s", DB_LABEL, x); \ - else \ - _LOG("chsmack -a %s %s", DB_LABEL, x); \ -} while (0) - -static int __set_db_permission(const char *path) -{ - int fd; - struct stat sb; - mode_t mode; - uid_t uid; - struct passwd pwd; - struct passwd *result; - char buf[BUF_SIZE]; - int ret; - - ret = getpwnam_r(APPFW_USER, &pwd, buf, sizeof(buf), &result); - if (result == NULL) { - if (ret == 0) - _LOGE("no such user: %s", APPFW_USER); - else - _LOGE("getpwnam_r failed: %d", errno); - return -1; - } - uid = pwd.pw_uid; - - ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result); - if (result == NULL) { - if (ret == 0) - _LOGE("no such user: %d", uid); - else - _LOGE("getpwuid_r failed: %d", errno); - return -1; - } - fd = open(path, O_RDONLY); - if (fd == -1) { - _LOGE("open %s failed: %d", path, errno); - return -1; - } - ret = fstat(fd, &sb); - if (ret == -1) { - _LOGE("stat %s failed: %d", path, errno); - close(fd); - return -1; - } - if (S_ISLNK(sb.st_mode)) { - _LOGE("%s is symlink!", path); - close(fd); - return -1; - } - ret = fchown(fd, uid, pwd.pw_gid); - if (ret == -1) { - _LOGE("fchown %s failed: %d", path, errno); - close(fd); - return -1; - } - - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; - if (strstr(path, CERT_DBPATH)) - mode |= S_IWOTH; - ret = fchmod(fd, mode); - if (ret == -1) { - _LOGE("fchmod %s failed: %d", path, errno); - close(fd); - return -1; - } - fsync(fd); - close(fd); - SET_SMACK_LABEL(path); - - return 0; -} - -static int __create_backup_flag(const char *path) -{ - int fd; - char temp_buf[8192] = {'\0', }; - - snprintf(temp_buf, sizeof(temp_buf), "%s.bck.flag", path); - - fd = open(temp_buf, O_CREAT | O_WRONLY, 0644); - if (fd == -1) { - _LOG("failed to create flag file %s, %d", temp_buf, errno); - return -1; - } - close(fd); - - return 0; -} - -static int __check_backup_flag(const char *path) -{ - char temp_buf[8192] = {'\0', }; - - snprintf(temp_buf, sizeof(temp_buf), "%s.bck.flag", path); - if (access(temp_buf, F_OK) != 0) - return -1; - - return 0; -} - -static int __remove_backup_flag(const char *path) -{ - char temp_buf[8192] = {'\0', }; - - snprintf(temp_buf, sizeof(temp_buf), "%s.bck.flag", path); - if (remove(temp_buf)) { - _LOG("cannot remove flag file(%s): %d", temp_buf, errno); - return -1; - } - - return 0; -} - -static int __check_and_restore_backup(const char *origin_path) { - char backup_path[BUF_SIZE]; - char buf[BUF_SIZE]; - snprintf(backup_path, BUF_SIZE, "%s.bck", origin_path); - - // if backup flag exists, it means the previous backup process aborted. - if (access(backup_path, F_OK) && __check_backup_flag(origin_path)) - return 0; - - if (access(origin_path, F_OK) == 0) { - if (remove(origin_path)) { - _LOG("cannot remove path(%s) : %s\n", origin_path, - strerror_r(errno, buf, sizeof(buf))); - return -1; - } - } - - if (rename(backup_path, origin_path)) { - _LOG("fail to rename %s to %s : %s\n", backup_path, origin_path, - strerror_r(errno, buf, sizeof(buf))); - return -1; - } - - return 0; -} - -static int __check_and_restore_backup_dbs() { - if (__check_and_restore_backup(DBPATH)) - return -1; - - if (__check_and_restore_backup(JOURNAL_DBPATH)) - return -1; - - if (__check_and_restore_backup(CERT_DBPATH)) - return -1; - - if (__check_and_restore_backup(JOURNAL_CERT_DBPATH)) - return -1; - - return 0; -} - -static int __backup_file(const char *src_path, const char *dest_path) -{ - int ret = 0; - int rc; - FILE *src = NULL; - FILE *dest = NULL; - char temp_buf[8192] = {'\0', }; - size_t size_of_char = sizeof(char); - size_t size_of_temp_buf = sizeof(temp_buf); - - retvm_if(src_path == NULL || dest_path == NULL, - -1, "Invalid parameters"); - - retvm_if(access(src_path, F_OK) != 0, -1, - "File(%s) is not exist", src_path); - - // if backup flag exists, it means the previous backup process aborted. - if (__check_backup_flag(src_path)) { - if (access(dest_path, F_OK) == 0) { - if (remove(dest_path)) - _LOG("Failed to remove uncompleted backup file " - "%s: %d", dest_path, errno); - return -1; - } - } else { - if (__create_backup_flag(src_path)) { - _LOG("failed to create backup flag"); - return -1; - } - } - - src = fopen(src_path, "r"); - tryvm_if(src == NULL, ret = -1, "Failed to open : %s\n", src_path); - - dest = fopen(dest_path, "w"); - tryvm_if(dest == NULL, ret = -1, "Failed to open : %s\n", dest_path); - - while (!feof(src)) { - rc = fread(temp_buf, size_of_char, size_of_temp_buf, src); - fwrite(temp_buf, size_of_char, rc, dest); - } - - fsync(fileno(dest)); - -catch: - if (src) - fclose(src); - - if (dest) - fclose(dest); - - __remove_backup_flag(src_path); - - return ret; -} - -static int __backup_db(const char *src_path, const char *dest_path) { - if (__backup_file(src_path, dest_path) != 0) - return -1; - - if (__set_db_permission(dest_path) != 0) - return -1; - - return 0; -} - -static int __make_backup_dbs() { - int ret = 0; - char parser_db_bck[BUF_SIZE]; - char parser_db_journal_bck[BUF_SIZE]; - char cert_db_bck[BUF_SIZE]; - char cert_db_journal_bck[BUF_SIZE]; - - snprintf(parser_db_bck, BUF_SIZE, "%s.bck", DBPATH); - snprintf(parser_db_journal_bck, BUF_SIZE, "%s.bck", JOURNAL_DBPATH); - snprintf(cert_db_bck, BUF_SIZE, "%s.bck", CERT_DBPATH); - snprintf(cert_db_journal_bck, BUF_SIZE, "%s.bck", JOURNAL_CERT_DBPATH); - - tryvm_if(__backup_db(DBPATH, parser_db_bck) == -1, - ret = -1, "Fail to backup [%s] to [%s]\n", - DBPATH, parser_db_bck); - - tryvm_if(__backup_db(JOURNAL_DBPATH, parser_db_journal_bck) == -1, - ret = -1, "Fail to backup [%s] to [%s]\n", - JOURNAL_DBPATH, parser_db_journal_bck); - - tryvm_if(__backup_db(CERT_DBPATH, cert_db_bck) == -1, - ret = -1, "Fail to backup [%s] to [%s]\n", - CERT_DBPATH, cert_db_bck); - - tryvm_if(__backup_db(JOURNAL_CERT_DBPATH, cert_db_journal_bck) == -1, - ret = -1, "Fail to backup [%s] to [%s]\n", - JOURNAL_CERT_DBPATH, cert_db_journal_bck); - - return 0; - -catch: - remove(parser_db_bck); - remove(parser_db_journal_bck); - remove(cert_db_bck); - remove(cert_db_journal_bck); - - return ret; -} - -static void __remove_backup_path(const char *origin_path) { - char backup_path[BUF_SIZE]; - - snprintf(backup_path, BUF_SIZE, "%s.bck", origin_path); - - if (remove(backup_path)) - _LOG("cannot remove backup file(%s): %d", backup_path, errno); -} - -static void __remove_backup_dbs() { - __remove_backup_path(DBPATH); - __remove_backup_path(JOURNAL_DBPATH); - __remove_backup_path(CERT_DBPATH); - __remove_backup_path(JOURNAL_CERT_DBPATH); -} - -int main(int argc, char *argv[]) -{ - GHashTable *preload_rw_table; - int ret = 0; - - ret = __check_and_restore_backup_dbs(); - retvm_if(ret < 0, -1, "__check_and_restore_backup_dbs is failed.\n"); - - ret = __make_backup_dbs(); - retvm_if(ret < 0, -1, "__make_backup_dbs is failed.\n"); - - /* check pkgmgr-fota dir, if it is not, then exit */ - ret = __check_pkgmgr_fota_dir(); - retvm_if(ret < 0, -1, "__check_pkgmgr_fota_dir is failed.\n"); - - /* clean pkgid list file */ - ret = __remove_pkgid_list(); - err_if(ret < 0, "remove[%s] failed\n", FOTA_RESULT_FILE); - - /* get pkgid from orginal pkgmgr db */ - ret = __get_pkgid_list_from_db_and_xml(); - retvm_if(ret < 0, -1, "__get_pkgid_list_from_db_and_xml is failed.\n"); - - //__get_pkginfo_from_opt(); - - ret = __check_tmp_all_preload_rw_pkg_list(); - retvm_if(ret < 0, -1, - "__check_tmp_all_preload_rw_pkg_list is failed.\n"); - - preload_rw_table = g_hash_table_new_full( - g_str_hash, g_str_equal, free, __free_pkginfo); - if (__fill_preload_rw_table(preload_rw_table) < 0) { - ret = __find_preload_rw_pkgid_from_db(preload_rw_table); - retvm_if(ret < 0, -1, "__find_preload_rw_pkgid_from_db is failed\n"); - } - - if (argc == 1) { - ret = __process_ro_fota(preload_rw_table); - if (ret < 0) { - g_hash_table_destroy(preload_rw_table); - _LOGE("__process_ro_fota is failed.\n"); - return EXIT_FAILURE; - } - ret = __process_rw_fota(preload_rw_table); - if (ret < 0) { - g_hash_table_destroy(preload_rw_table); - _LOGE("__process_rw_fota is failed.\n"); - return EXIT_FAILURE; - } - } else { - if (strcmp(argv[1], "-rof") == 0) { - ret = __process_ro_fota(preload_rw_table); - if (ret < 0) { - g_hash_table_destroy(preload_rw_table); - _LOGE("__process_ro_fota is failed.\n"); - return EXIT_FAILURE; - } - } else if (strcmp(argv[1], "-rwf") == 0) { - ret = __process_rw_fota(preload_rw_table); - if (ret < 0) { - g_hash_table_destroy(preload_rw_table); - _LOGE("__process_rw_fota is failed.\n"); - return EXIT_FAILURE; - } - } else { - fprintf(stderr, "not supported operand\n"); - } - } - __make_preload_rw_list(preload_rw_table); - g_hash_table_destroy(preload_rw_table); - __remove_backup_dbs(); - - return EXIT_SUCCESS; -} diff --git a/src/pkg_upgrade/src/backend_invoker.cc b/src/pkg_upgrade/src/backend_invoker.cc new file mode 100644 index 0000000..d5db0f1 --- /dev/null +++ b/src/pkg_upgrade/src/backend_invoker.cc @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "backend_invoker.hh" +#include "logging.hh" + +namespace common_fota { + +BackendInvoker::BackendInvoker(std::string pkgid, PkgType type, PkgLocation loc, + PkgOperation op, bool removable) { + if (type == PkgType::WGT) { + parameters_.push_back("/usr/bin/wgt-backend"); + } else { + parameters_.push_back("/usr/bin/tpk-backend"); + } + + if (op == PkgOperation::INSTALL || op == PkgOperation::UPDATE) { + parameters_.push_back("-y"); + parameters_.push_back(std::move(pkgid)); + if (loc == PkgLocation::RO) { + parameters_.push_back("--preload"); + parameters_.push_back("--partial-rw"); + } else { + if (!removable) + parameters_.push_back("--no-remove"); + parameters_.push_back("--preload-rw"); + } + parameters_.push_back("--skip-check-reference"); + } else if (op == PkgOperation::UNINSTALL) { + parameters_.push_back("-d"); + parameters_.push_back(std::move(pkgid)); + if (loc == PkgLocation::RO) + parameters_.push_back("--preload"); + parameters_.push_back("--force-remove"); + parameters_.push_back("--partial-rw"); + } else if (op == PkgOperation::UNINSTALL_KEEP_RW_DATA) { + parameters_.push_back("-d"); + parameters_.push_back(std::move(pkgid)); + if (loc == PkgLocation::RO) + parameters_.push_back("--preload"); + parameters_.push_back("--force-remove"); + parameters_.push_back("--keep-rwdata"); + } +} + +int BackendInvoker::Run() const { + const char* param[parameters_.size() + 1] = { nullptr, }; + + int i = 0; + for (auto& str : parameters_) { + param[i++] = str.c_str(); + } + + return XSystem(param); +} + +int BackendInvoker::XSystem(const char *argv[]) { + int status = 0; + pid_t pid; + + std::string cmd; + for (int i = 0; argv[i] != nullptr; i++) { + cmd += argv[i]; + cmd += " "; + } + LOG(DEBUG) << "Cmd: " << cmd; + + pid = fork(); + switch (pid) { + case -1: + LOG(ERROR) << "fork failed "; + return -1; + case 0: + /* child */ + execvp(argv[0], (char *const *)argv); + _exit(-1); + default: + /* parent */ + break; + } + if (waitpid(pid, &status, 0) == -1) { + LOG(ERROR) << "waitpid failed"; + return -1; + } + if (WIFSIGNALED(status)) { + LOG(ERROR) << "signal"; + return -1; + } + if (!WIFEXITED(status)) { + LOG(ERROR) << "should not happen"; + return -1; + } + + return WEXITSTATUS(status); +} + +} // namespace common_fota \ No newline at end of file diff --git a/src/pkg_upgrade/src/file_logbackend.cc b/src/pkg_upgrade/src/file_logbackend.cc new file mode 100644 index 0000000..48c41dd --- /dev/null +++ b/src/pkg_upgrade/src/file_logbackend.cc @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "logging.hh" +#include "file_logbackend.hh" + + +namespace utils { + +FileLogBackend::FileLogBackend(std::string file_name, int rotation_size, + int max_rotation) + : file_name_(std::move(file_name)), rotation_size_(rotation_size), + max_rotation_(max_rotation), log_stream_( + std::unique_ptr(new std::ostringstream())) { +} + + +void FileLogBackend::WriteLog(LogLevel level, const std::string& /* tag */, + const std::string& logstr) { + if (level != LogLevel::LOG_DEBUG) + *log_stream_ << GetTimeStamp() << GetPid() << logstr << std::endl; +} + +void FileLogBackend::WriteLogToFile() { + if (file_name_.empty()) + return; + + int size = GetFileSize(file_name_); + if (size > rotation_size_) + if (!Rotate()) + return; + + std::ofstream ofs(file_name_.c_str(), std::ios::app); + ofs << log_stream_->str(); + ofs.close(); + + // clean the log stream + log_stream_->str(""); + log_stream_->clear(); +} + +bool FileLogBackend::Rotate() { + for (int i = max_rotation_; i > 0; i--) { + std::string old_log = file_name_ + "." + std::to_string(i); + // the oldest log will be removed + if (i == max_rotation_) { + if (std::remove(old_log.c_str()) != 0) + return false; + } else { + std::string new_log = file_name_ + "." + std::to_string(i + 1); + if (std::rename(old_log.c_str(), new_log.c_str()) != 0) + return false; + } + } + std::string new_log = file_name_ + ".1"; + if (std::rename(file_name_.c_str(), new_log.c_str()) != 0) + return false; + + return true; +} + +int FileLogBackend::GetFileSize(const std::string& file_name) { + struct stat sb; + int ret = stat(file_name.c_str(), &sb); + return ret == 0 ? sb.st_size : -1; +} + +std::string FileLogBackend::GetTimeStamp() { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + time_t seconds = ts.tv_sec; + struct tm gmt; + if (!gmtime_r(&seconds, &gmt)) + return "|"; + int32_t miliseconds = ts.tv_nsec / 1000000; + + char buf[32]; + strftime(buf, sizeof(buf), "%Y%m%d.%H%M%S", &gmt); + char timestamp[64]; + snprintf(timestamp, sizeof(timestamp), "%s.%03dUTC|", buf, miliseconds); + + return timestamp; +} + +std::string FileLogBackend::GetPid() { + return std::to_string(getpid()) + "|"; +} + +} // namespace utils diff --git a/src/pkg_upgrade/src/logging.cc b/src/pkg_upgrade/src/logging.cc new file mode 100644 index 0000000..6da958c --- /dev/null +++ b/src/pkg_upgrade/src/logging.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "logging.hh" + +namespace utils { + +log_priority LogLevelToPriority(LogLevel level) { + switch (level) { + case LogLevel::LOG_ERROR: + return log_priority::DLOG_ERROR; + case LogLevel::LOG_WARNING: + return log_priority::DLOG_WARN; + case LogLevel::LOG_INFO: + return log_priority::DLOG_INFO; + case LogLevel::LOG_DEBUG: + return log_priority::DLOG_DEBUG; + default: + return log_priority::DLOG_UNKNOWN; + } +} + +} // namespace utils diff --git a/src/pkg_upgrade/src/main.cc b/src/pkg_upgrade/src/main.cc new file mode 100644 index 0000000..9d2eea2 --- /dev/null +++ b/src/pkg_upgrade/src/main.cc @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pkg_finder.hh" +#include "upgrader.hh" + +int main(int argc, char *argv[]) { + common_fota::PkgFinder finder; + common_fota::Upgrader upgrader; + + if (!upgrader.Process(&finder)) + return -1; + + return 0; +} diff --git a/src/pkg_upgrade/src/pkg_finder.cc b/src/pkg_upgrade/src/pkg_finder.cc new file mode 100644 index 0000000..923378a --- /dev/null +++ b/src/pkg_upgrade/src/pkg_finder.cc @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "logging.hh" +#include "pkg_finder.hh" +#include "backend_invoker.hh" + +#define ASCII(s) reinterpret_cast(s) +#define XMLCHAR(s) reinterpret_cast(s) +#define USR_MANIFEST_DIRECTORY tzplatform_getenv(TZ_SYS_RO_PACKAGES) +#define PRELOAD_RW_LIST_FILE \ + tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \ + "pkgmgr/fota/.all_preload_rw_list") +#define ALL_PRELOAD_RW_PKG_LIST "opt/usr/share/.all_preload_rw_list" +#define PKGMGR_FOTA_PATH tzplatform_mkpath(TZ_SYS_GLOBALUSER_DATA, \ + "pkgmgr/fota") + + +using namespace std; + +namespace { +constexpr char kOptZipFile[] = "/usr/system/RestoreDir/opt.zip"; +constexpr int kBufSize = 1024; +constexpr char kSeperatorEnd = '"'; +constexpr char kSeperatorMid = ':'; +constexpr char kTokenTypeStr[] = "type="; +constexpr char kTokenPkgidStr[] = "package="; +constexpr char kTokenVersionStr[] = "version="; +constexpr char kTokenRemoveStr[] = "removable="; +} // namespace + +namespace common_fota { + +PkgFinder::PkgFinder() { + xmlInitParser(); + manifest_dir_ = USR_MANIFEST_DIRECTORY; + preload_rw_list_path_ = PRELOAD_RW_LIST_FILE; + if (access(kOptZipFile, F_OK) != 0) + return; + + int ret = UnzipFileOnlyToPath(ALL_PRELOAD_RW_PKG_LIST, PKGMGR_FOTA_PATH); + if (ret != 0) { + LOG(ERROR) << "Failed to unzip file from backup"; + return; + } +} + +PkgFinder::~PkgFinder() { + xmlCleanupParser(); +} + +int PkgFinder::UnzipFileOnlyToPath(const char* dest_path, const char* unzip_to) { + const char* unzip_argv[] = { "/usr/bin/unzip", "-joXqq", + kOptZipFile, dest_path, "-d", unzip_to, nullptr }; + return BackendInvoker::XSystem(unzip_argv); +} + +int PkgFinder::Find() { + if (FindPreloadPkgidFromDb(true) != 0) { + LOG(ERROR) << "FindPreloadPkgidFromDb(true) failed"; + return -1; + } + + if (FindPreloadPkgidFromDb(false) != 0) { + LOG(ERROR) << "FindPreloadPkgidFromDb(false) failed"; + return -1; + } + + if (FindPreloadPkgidFromXml(manifest_dir_) != 0) { + LOG(ERROR) << "FindPreloadPkgidFromXml(" << manifest_dir_ << ") failed"; + return -1; + } + + if (FindPreloadPkgidFromFile() != 0) { + LOG(ERROR) << "FindPreloadPkgidFromFile failed"; + return -1; + } + + return 0; +} + +void PkgFinder::SetManifestDir(std::string dir) { + manifest_dir_ = std::move(dir); +} + +void PkgFinder::SetPreloadRwListPath(std::string path) { + preload_rw_list_path_ = std::move(path); +} + +int PkgFinder::PkgidListCb(const pkgmgrinfo_pkginfo_h handle, void* user_data) { + char* pkgid = nullptr; + int ret = -1; + ret = pkgmgrinfo_pkginfo_get_pkgid(handle, &pkgid); + if (ret < 0) + return 0; + + char* version = nullptr; + ret = pkgmgrinfo_pkginfo_get_version(handle, &version); + if (ret < 0) + return 0; + + char* type = nullptr; + ret = pkgmgrinfo_pkginfo_get_type(handle, &type); + if (ret < 0) + return 0; + + PkgFinder* finder = static_cast(user_data); + finder->old_pkgs_.emplace_back(pkgid, version, type, finder->read_only_); + return 0; +} + +int PkgFinder::FindPreloadPkgidFromDb(bool read_only) { + int ret = 0; + pkgmgrinfo_pkginfo_filter_h handle = nullptr; + + ret = pkgmgrinfo_pkginfo_filter_create(&handle); + if (ret != PMINFO_R_OK) { + LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_create failed " << ret; + return -1; + } + + ret = pkgmgrinfo_pkginfo_filter_add_bool(handle, + PMINFO_PKGINFO_PROP_PACKAGE_PRELOAD, 1); + if (ret != PMINFO_R_OK) { + LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_add_bool failed " << ret; + return -1; + } + + ret = pkgmgrinfo_pkginfo_filter_add_bool(handle, + PMINFO_PKGINFO_PROP_PACKAGE_READONLY, read_only ? 1 : 0); + if (ret != PMINFO_R_OK) { + LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_add_bool failed " << ret; + return -1; + } + + read_only_ = read_only; + ret = pkgmgrinfo_pkginfo_filter_foreach_pkginfo(handle, + PkgidListCb, this); + if (ret != PMINFO_R_OK) { + LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_foreach_pkginfo failed " << ret; + return -1; + } + + ret = pkgmgrinfo_pkginfo_filter_destroy(handle); + if (ret != PMINFO_R_OK) { + LOG(ERROR) << "pkgmgrinfo_pkginfo_filter_destroy failed " << ret; + return -1; + } + + return 0; +} + +int PkgFinder::FindPreloadPkgidFromXml( + const string& xml_directory) { + DIR* dir; + struct dirent* entry = nullptr; + + dir = opendir(xml_directory.c_str()); + if (!dir) { + LOG(ERROR) << "opendir(" << xml_directory << ") failed "; + return -1; + } + + while ((entry = readdir(dir)) != nullptr) { + if (entry->d_name[0] == '.') continue; + + string manifest = GetValidManifest(entry->d_name); + if (manifest.empty()) { + continue; + } + + string buf = xml_directory + "/" + manifest; + string pkgid = FindInfoFromXml(buf, "package"); + string version = FindInfoFromXml(buf, "version"); + + if (version.empty()) + version = "0.0.1"; + + string type = FindInfoFromXml(buf, "type"); + if (type.empty()) + type = "tpk"; + + new_pkgs_.emplace_back(pkgid, version, type, true); + } + + closedir(dir); + + return 0; +} + +string PkgFinder::GetValidManifest(string manifest) { + size_t found = manifest.rfind(".xml"); + if (found == string::npos) + return ""; + + return manifest; +} + +string PkgFinder::FindInfoFromXml(const string& manifest, + const string& find_info) { + const xmlChar* node; + xmlTextReaderPtr reader; + string info_val; + xmlChar* tmp = nullptr; + + reader = xmlReaderForFile(manifest.c_str(), nullptr, 0); + + if (reader) { + if (MoveToChildElement(reader, -1)) { + node = xmlTextReaderConstName(reader); + if (!node) { + LOG(ERROR) << "xmlTextReaderConstName value is NULL"; + goto end; + } + + if (!strcmp(ASCII(node), "manifest")) { + tmp = xmlTextReaderGetAttribute(reader, + XMLCHAR(find_info.c_str())); + if (tmp) { + info_val = ASCII(tmp); + free(tmp); + tmp = nullptr; + } + } else { + LOG(ERROR) << "Manifest Node is not found"; + } + } + } else { + LOG(ERROR) << "xmlReaderForFile value is NULL"; + } + +end: + if (reader) + xmlFreeTextReader(reader); + + return info_val; +} + +int PkgFinder::MoveToChildElement(xmlTextReaderPtr reader, + int depth) { + int ret = xmlTextReaderRead(reader); + int cur = xmlTextReaderDepth(reader); + while (ret == 1) { + switch (xmlTextReaderNodeType(reader)) { + case XML_READER_TYPE_ELEMENT: + if (cur == depth + 1) + return 1; + break; + case XML_READER_TYPE_TEXT: + if (cur == depth + 1) + return 0; + break; + case XML_READER_TYPE_END_ELEMENT: + if (cur == depth) + return 0; + break; + default: + if (cur <= depth) + return 0; + break; + } + + ret = xmlTextReaderRead(reader); + cur = xmlTextReaderDepth(reader); + } + return ret; +} + +int PkgFinder::FindPreloadPkgidFromFile() { + char buf[kBufSize] = {0}; + FILE *fp = nullptr; + + fp = fopen(preload_rw_list_path_.c_str(), "r"); + if (fp == nullptr) { + LOG(INFO) << "no preload rw list file"; + return 0; + } + + while (fgets(buf, kBufSize, fp) != NULL) { + StrTrim(buf); + AddRwPkgInfoFromFile(buf); + } + + fclose(fp); + return 0; +} + +void PkgFinder::AddRwPkgInfoFromFile(const char* info_str) { + if (info_str == nullptr) + return; + + string pkgid = GetToken(info_str, kTokenPkgidStr); + string version = GetToken(info_str, kTokenVersionStr); + string type = GetToken(info_str, kTokenTypeStr); + string removable = GetToken(info_str, kTokenRemoveStr); + + transform(type.begin(), type.end(), type.begin(), + [](unsigned char c) { + return tolower(c); + }); + + transform(removable.begin(), removable.end(), removable.begin(), + [](unsigned char c) { + return tolower(c); + }); + + if (removable == "false") + new_pkgs_.emplace_back(pkgid, version, type, false, false); + else + new_pkgs_.emplace_back(pkgid, version, type, false, true); +} + +string PkgFinder::GetToken(const char* pBuf, const char* pKey) { + const char *p = nullptr; + const char *pStart = nullptr; + const char *pEnd = nullptr; + + p = strstr(pBuf, pKey); + if (p == nullptr) + return ""; + + pStart = p + strlen(pKey); + pEnd = strchr(pStart, kSeperatorEnd); + if (pEnd == nullptr) { + pEnd = strchr(pStart, kSeperatorMid); + if (pEnd == nullptr) + return ""; + } + + size_t len = pEnd - pStart; + if (len <= 0) + return ""; + + string res(pStart, len); + + return res; +} + +void PkgFinder::StrTrim(char *input) { + char *trim_str = input; + + if (input == nullptr) + return; + + while (*input != 0) { + if (!isspace(*input)) { + *trim_str = *input; + trim_str++; + } + input++; + } + + *trim_str = 0; + return; +} + +} // common_fota \ No newline at end of file diff --git a/src/pkg_upgrade/src/pkg_upgrader.cc b/src/pkg_upgrade/src/pkg_upgrader.cc new file mode 100644 index 0000000..2987e93 --- /dev/null +++ b/src/pkg_upgrade/src/pkg_upgrader.cc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "pkg_upgrader.hh" + +namespace common_fota { + +PkgUpgrader::PkgUpgrader(const PkgContext& context, PkgOperation pkg_op) + : type_(context.GetType()), loc_(context.GetLocation()), op_(pkg_op), + id_(context.GetId()), version_(context.GetVersion()), + backend_(context.GetId(), context.GetType(), context.GetLocation(), + pkg_op, context.IsRemovable()) { +} + +PkgUpgrader::PkgUpgrader(std::string id) + : type_(PkgType::UNKNOWN), loc_(PkgLocation::UNKNOWN), + op_(PkgOperation::COMPLEX), id_(std::move(id)) { +} + +PkgType PkgUpgrader::GetType() const { + return type_; +} + +PkgLocation PkgUpgrader::GetLocation() const { + return loc_; +} + +PkgOperation PkgUpgrader::GetOperation() const { + return op_; +} + +std::string PkgUpgrader::GetId() const { + return id_; +} + +std::string PkgUpgrader::GetVersion() const { + return version_; +} + +const BackendInvoker& PkgUpgrader::GetBackendInvoker() const { + return backend_; +} + +int PkgUpgrader::CompareVersion(const PkgUpgrader& pkg) const { + pkgmgrinfo_version_compare_type compare = PMINFO_VERSION_OLD; + int ret = pkgmgrinfo_compare_package_version(version_.c_str(), + pkg.GetVersion().c_str(), &compare); + if (ret != 0) + return -1; + + if (compare == PMINFO_VERSION_NEW) + return -1; + else if (compare == PMINFO_VERSION_OLD) + return 1; + + return 0; +} + + +} // common_fota \ No newline at end of file diff --git a/src/pkg_upgrade/src/pkg_upgrader_factory.cc b/src/pkg_upgrade/src/pkg_upgrader_factory.cc new file mode 100644 index 0000000..0c8848e --- /dev/null +++ b/src/pkg_upgrade/src/pkg_upgrader_factory.cc @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "logging.hh" +#include "pkg_upgrader_factory.hh" +#include "ro2rw_upgrader.hh" +#include "rw2ro_upgrader.hh" +#include "rw_upgrader.hh" +#include "simple_upgrader.hh" + +using namespace std; + +namespace common_fota { + +list> PkgUpgraderFactory::MakeList(PkgFinder* finder) { + if (finder->Find() != 0) { + LOG(ERROR) << "PkgFinder::Find() failed"; + return {}; + } + return Merge(finder->GetOldPkgs(), finder->GetNewPkgs()); +} + +list> PkgUpgraderFactory::Merge( + const list& old_pkgs, const list& new_pkgs) { + list> pkgs; + + for (auto& new_pkg : new_pkgs) { + const auto* old_pkg = FindPkgById(old_pkgs, new_pkg.GetId()); + if (old_pkg != nullptr) { + // UPDATE + if (old_pkg->IsReadOnly() && new_pkg.IsReadOnly()) { + // RO to RO + pkgs.emplace_back(new SimpleUpgrader(new_pkg, PkgOperation::UPDATE)); + } else if (!old_pkg->IsReadOnly() && !new_pkg.IsReadOnly()) { + // RW to RW + pkgs.emplace_back(new RwUpgrader( + unique_ptr(new SimpleUpgrader(new_pkg, + PkgOperation::UPDATE)))); + } else if (!old_pkg->IsReadOnly() && new_pkg.IsReadOnly()) { + // RW to RO + pkgs.emplace_back(new Rw2RoUpgrader( + unique_ptr(new SimpleUpgrader(*old_pkg, + PkgOperation::UNINSTALL_KEEP_RW_DATA)), + unique_ptr(new SimpleUpgrader(new_pkg, + PkgOperation::INSTALL)) + )); + } else if (old_pkg->IsReadOnly() && !new_pkg.IsReadOnly()) { + // RO to RW + pkgs.emplace_back(new Ro2RwUpgrader( + unique_ptr(new SimpleUpgrader(*old_pkg, + PkgOperation::UNINSTALL_KEEP_RW_DATA)), + unique_ptr(new SimpleUpgrader(new_pkg, + PkgOperation::INSTALL)) + )); + } + } else { + // INSTALL + if (new_pkg.IsReadOnly()) { + // RO + pkgs.emplace_back(new SimpleUpgrader(new_pkg, PkgOperation::INSTALL)); + } else { + // RW + pkgs.emplace_back(new RwUpgrader( + unique_ptr(new SimpleUpgrader(new_pkg, + PkgOperation::INSTALL)))); + } + } + } + + for (auto& old_pkg : old_pkgs) { + const auto* new_pkg = FindPkgById(new_pkgs, old_pkg.GetId()); + if (new_pkg == nullptr) { + // UNINSTALL + if (old_pkg.IsReadOnly()) { + pkgs.emplace_back(new SimpleUpgrader(old_pkg, + PkgOperation::UNINSTALL)); + } + } + } + + return pkgs; +} + +const PkgContext* PkgUpgraderFactory::FindPkgById( + const list& pkgs, string id) { + for (auto& pkg : pkgs) { + if (pkg.GetId() == id) + return &pkg; + } + + return nullptr; +} + +} // common_fota \ No newline at end of file diff --git a/src/pkg_upgrade/src/ro2rw_upgrader.cc b/src/pkg_upgrade/src/ro2rw_upgrader.cc new file mode 100644 index 0000000..192ad67 --- /dev/null +++ b/src/pkg_upgrade/src/ro2rw_upgrader.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "logging.hh" +#include "ro2rw_upgrader.hh" + +namespace { +constexpr char kOptZipFile[] = "/usr/system/RestoreDir/opt.zip"; +} // namespace + +namespace common_fota { + +Ro2RwUpgrader::Ro2RwUpgrader(std::unique_ptr old_pkg, + std::unique_ptr new_pkg) + : PkgUpgrader(new_pkg->GetId()), old_pkg_(std::move(old_pkg)), + new_pkg_(std::move(new_pkg)) { +} + +bool Ro2RwUpgrader::Upgrade() { + if (old_pkg_.get() != nullptr) { + if (!old_pkg_->Upgrade()) { + LOG(ERROR) << "old_pkg_->Upgrade() failed"; + return false; + } + } + + if (UnzipPkgFromZip(new_pkg_->GetId().c_str()) != 0) { + LOG(ERROR) << "UnzipPkgFromZip(" << new_pkg_->GetId() << ") failed"; + return false; + } + + if (new_pkg_.get() != nullptr) { + if (!new_pkg_->Upgrade()) { + LOG(ERROR) << "new_pkg_->Upgrade() failed"; + return false; + } + } + + return true; +} + +int Ro2RwUpgrader::UnzipFiles(const char* dest_path) { + const char* unzip_argv[] = { "/usr/bin/unzip", "-oXqq", kOptZipFile, + dest_path, "-d", "/", nullptr }; + int ret = BackendInvoker::XSystem(unzip_argv); + + return ret; +} + +int Ro2RwUpgrader::UnzipXml(const std::string& pkgid) { + std::string path = "opt/share/packages/" + pkgid + ".xml"; + int ret = UnzipFiles(path.c_str()); + + return ret; +} + +int Ro2RwUpgrader::UnzipData(const std::string& pkgid, const std::string& dest) { + std::string path = dest + pkgid + "/*"; + int ret = UnzipFiles(path.c_str()); + if (ret != 0) + return -1; + + return 0; +} + +int Ro2RwUpgrader::UnzipPkgFromZip(const std::string& pkgid) { + int ret = -1; + + ret = UnzipXml(pkgid); + if (ret != 0) { + LOG(ERROR) << "UnzipXml(" << pkgid << ") failed"; + return ret; + } + + ret = UnzipData(pkgid, "opt/usr/globalapps/"); + if (ret != 0) { + LOG(ERROR) << "UnzipData(" << pkgid << ") failed"; + return ret; + } + + ret = UnzipData(pkgid, "opt/etc/skel/apps_rw/"); + if (ret != 0) { + LOG(ERROR) << "UnzipData(" << pkgid << ") failed"; + return ret; + } + + return 0; +} + +} // common_fota \ No newline at end of file diff --git a/src/pkg_upgrade/src/rw2ro_upgrader.cc b/src/pkg_upgrade/src/rw2ro_upgrader.cc new file mode 100644 index 0000000..b1f200a --- /dev/null +++ b/src/pkg_upgrade/src/rw2ro_upgrader.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "logging.hh" +#include "rw2ro_upgrader.hh" + +namespace common_fota { + +Rw2RoUpgrader::Rw2RoUpgrader(std::unique_ptr old_pkg, + std::unique_ptr new_pkg) + : PkgUpgrader(new_pkg->GetId()), old_pkg_(std::move(old_pkg)), + new_pkg_(std::move(new_pkg)) { +} + +bool Rw2RoUpgrader::Upgrade() { + if (new_pkg_->CompareVersion(*old_pkg_) >= 0) { + if (!old_pkg_->Upgrade()) { + LOG(ERROR) << "old_pkg_->Upgrade() failed"; + return false; + } + + if (!new_pkg_->Upgrade()) { + LOG(ERROR) << "new_pkg_->Upgrade() failed"; + return false; + } + } else { + LOG(DEBUG) << "new_pkg version < old_pkg version"; + } + + return true; +} + +} // common_fota \ No newline at end of file diff --git a/src/pkg_upgrade/src/simple_upgrader.cc b/src/pkg_upgrade/src/simple_upgrader.cc new file mode 100644 index 0000000..5ee0ef2 --- /dev/null +++ b/src/pkg_upgrade/src/simple_upgrader.cc @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "simple_upgrader.hh" + +namespace common_fota { + +SimpleUpgrader::SimpleUpgrader(const PkgContext& context, + PkgOperation pkg_op) + : PkgUpgrader(context, pkg_op) { +} + +bool SimpleUpgrader::Upgrade() { + if (GetBackendInvoker().Run() == 0) + return true; + return false; +} + +} // common_fota \ No newline at end of file diff --git a/src/pkg_upgrade/src/upgrader.cc b/src/pkg_upgrade/src/upgrader.cc new file mode 100644 index 0000000..9e83b98 --- /dev/null +++ b/src/pkg_upgrade/src/upgrader.cc @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "logging.hh" +#include "pkg_upgrader_factory.hh" +#include "upgrader.hh" + +using namespace std; + +namespace { +constexpr char kLogFileName[] = "/var/log/appfw/app-installers/fota.log"; +constexpr int kLogRotationSize = 1024 * 1024; // 1MB +constexpr int kLogMaximumRotation = 3; +constexpr int kBufSize = 1024; +constexpr char kDbLabel[] = "User::Home"; +constexpr char kAppfwUser[] = "app_fw"; + +class File { + public: + File(const string& path) { + fd_ = open(path.c_str(), O_RDONLY); + } + + File(const string& path, int flags, mode_t mode) { + fd_ = open(path.c_str(), flags, mode); + } + + ~File() { + if (fd_ != -1) + close(fd_); + } + + int GetFd() const { + return fd_; + } + + int FStat(struct stat* statbuf) { + return fstat(fd_, statbuf); + } + + int FChOwn(uid_t owner, gid_t group) { + return fchown(fd_, owner, group); + } + + int FChMod(mode_t mode) { + return fchmod(fd_, mode); + } + + int FSync() { + return fsync(fd_); + } + + private: + int fd_ = -1; +}; + +} + +namespace common_fota { + +Upgrader::Upgrader() { + logger_ = shared_ptr(new utils::FileLogBackend( + ::kLogFileName, ::kLogRotationSize, ::kLogMaximumRotation)); + ::utils::LogCore::GetCore().AddLogBackend(logger_); + string path = tzplatform_getenv(TZ_SYS_DB); + SetDbPath(path); +} + +void Upgrader::SetDbPath(const string& path) { + parser_db_ = path + "/.pkgmgr_parser.db"; + parser_db_journal_ = path + "/.pkgmgr_parser.db-journal"; + cert_db_ = path + "/.pkgmgr_cert.db"; + cert_db_journal_ = path + "/.pkgmgr_cert.db-journal"; +} + +bool Upgrader::Process(PkgFinder* finder) { + if (CheckAndRestoreBackupDbs() != 0) { + LOG(ERROR) << "CheckAndRestoreBackupDbs failed"; + return false; + } + + if (MakeBackupDbs() != 0) { + LOG(ERROR) << "MakeBackupDbs failed"; + return false; + } + + PkgUpgraderFactory factory; + auto list = factory.MakeList(finder); + + for(auto& pkg : list) { + if(pkg->Upgrade()) { + LOG(DEBUG) << "upgrade success (" << pkg->GetId() << ")"; + success_list_.push_back(move(pkg)); + } else { + LOG(ERROR) << "upgrade failed (" << pkg->GetId() << ")"; + failure_list_.push_back(move(pkg)); + } + } + + RemoveBackupDbs(); + + logger_->WriteLog(::utils::LogLevel::LOG_INFO, "", "Upgrade Done"); + logger_->WriteLogToFile(); + return true; +} + +const list>& Upgrader::GetSuccessList() const { + return success_list_; +} + +const list>& Upgrader::GetFailureList() const { + return failure_list_; +} + +int Upgrader::CheckAndRestoreBackupDbs() { + if (CheckAndRestoreBackup(parser_db_)) + return -1; + + if (CheckAndRestoreBackup(parser_db_journal_)) + return -1; + + if (CheckAndRestoreBackup(cert_db_)) + return -1; + + if (CheckAndRestoreBackup(cert_db_journal_)) + return -1; + + return 0; +} + +int Upgrader::CheckAndRestoreBackup(const string& origin_path) { + string backup_path = origin_path + ".bck"; + + // if backup flag exists, it means the previous backup process aborted. + if (access(backup_path.c_str(), F_OK) && CheckBackupFlag(origin_path)) + return 0; + + if (access(origin_path.c_str(), F_OK) == 0) { + if (remove(origin_path.c_str())) { + LOG(ERROR) << "cannot remove path(" << origin_path << " : " << errno; + return -1; + } + } + + if (rename(backup_path.c_str(), origin_path.c_str())) { + LOG(ERROR) << "fail to rename " << backup_path << " to " << + origin_path << errno; + return -1; + } + + return 0; +} + +int Upgrader::SetDbPermission(const string& path) { + struct stat sb; + struct passwd pwd; + struct passwd *result; + char buf[kBufSize]; + + int ret = getpwnam_r(kAppfwUser, &pwd, buf, sizeof(buf), &result); + if (result == NULL) { + LOG(ERROR) << "getpwnam_r failed: " << errno; + return -1; + } + uid_t uid = pwd.pw_uid; + + ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &result); + if (result == NULL) { + LOG(ERROR) << "getpwuid_r failed: " << errno; + return -1; + } + + ::File file(path); + + if (file.GetFd() == -1) { + LOG(ERROR) << "open(" << path << "failed: " << errno; + return -1; + } + + ret = file.FStat(&sb); + if (ret == -1) { + LOG(ERROR) << "stat " << path << "failed: " << errno; + return -1; + } + if (S_ISLNK(sb.st_mode)) { + LOG(ERROR) << path << " is symlink!"; + return -1; + } + ret = file.FChOwn(uid, pwd.pw_gid); + if (ret == -1) { + LOG(ERROR) << "fchown " << path << " failed: " << errno; + return -1; + } + + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; + if (path.find(cert_db_) != string::npos) + mode |= S_IWOTH; + ret = file.FChMod(mode); + if (ret == -1) { + LOG(ERROR) << "fchmod " << path << " failed: " << errno; + return -1; + } + file.FSync(); + if (smack_setlabel(path.c_str(), kDbLabel, SMACK_LABEL_ACCESS)) + LOG(ERROR) << "failed chsmack -a " << kDbLabel << " " << path; + + return 0; +} + +int Upgrader::CreateBackupFlag(const string& path) { + string flag = path + ".bck.flag"; + + ::File file(flag, O_CREAT | O_WRONLY, 0644); + if (file.GetFd() == -1) { + LOG(ERROR) << "failed to create flag file " << flag << ", " << errno; + return -1; + } + + return 0; +} + +int Upgrader::CheckBackupFlag(const string& path) { + string flag = path + ".bck.flag"; + + if (access(flag.c_str(), F_OK) != 0) + return -1; + + return 0; +} + +int Upgrader::RemoveBackupFlag(const string& path) { + string flag = path + ".bck.flag"; + + if (remove(flag.c_str())) { + LOG(ERROR) << "cannot remove flag file(" << flag << ") " << errno; + return -1; + } + + return 0; +} + +int Upgrader::BackupFile(const string& src_path, const string& dest_path) { + char temp_buf[8192] = {'\0', }; + size_t size_of_char = sizeof(char); + size_t size_of_temp_buf = sizeof(temp_buf); + + if (access(src_path.c_str(), F_OK) != 0) { + LOG(ERROR) << "File(" << src_path << ") is not exist"; + return -1; + } + + // if backup flag exists, it means the previous backup process aborted. + if (CheckBackupFlag(src_path)) { + if (access(dest_path.c_str(), F_OK) == 0) { + if (remove(dest_path.c_str())) { + LOG(ERROR) << "Failed to remove uncompleted backup file " << + dest_path << " : " << errno; + return -1; + } + } + } else { + if (CreateBackupFlag(src_path)) { + LOG(ERROR) << "failed to create backup flag"; + return -1; + } + } + + FILE* src = fopen(src_path.c_str(), "r"); + unique_ptr src_auto(src, fclose); + if (src == nullptr) { + LOG(ERROR) << "Failed to open : " << src_path; + return -1; + } + + FILE* dest = fopen(dest_path.c_str(), "w"); + unique_ptr dest_auto(dest, fclose); + if (dest == nullptr) { + LOG(ERROR) << "Failed to open : " << dest_path; + return -1; + } + + while (!feof(src)) { + int rc = fread(temp_buf, size_of_char, size_of_temp_buf, src); + fwrite(temp_buf, size_of_char, rc, dest); + } + + fsync(fileno(dest)); + RemoveBackupFlag(src_path); + + return 0; +} + +int Upgrader::BackupDb(const string& src_path, const string& dest_path) { + if (BackupFile(src_path, dest_path) != 0) + return -1; + + if (SetDbPermission(dest_path) != 0) + return -1; + + return 0; +} + +int Upgrader::MakeBackupDbs() { + string parser_db_bck = parser_db_ + ".bck"; + string parser_db_journal_bck = parser_db_journal_ + ".bck"; + string cert_db_bck = cert_db_ + ".bck"; + string cert_db_journal_bck = cert_db_journal_ + ".bck"; + + if (BackupDb(parser_db_, parser_db_bck) == -1 ) { + LOG(ERROR) << "Fail to backup [" << parser_db_ << "] to [" << parser_db_bck << + "]"; + goto CATCH; + } + + if (BackupDb(parser_db_journal_, parser_db_journal_bck) == -1) { + LOG(ERROR) << "Fail to backup [" << parser_db_journal_ << "] to [" << + parser_db_journal_bck << "]"; + goto CATCH; + } + + if (BackupDb(cert_db_, cert_db_bck) == -1) { + LOG(ERROR) << "Fail to backup [" << cert_db_ << "] to [" << + cert_db_bck << "]"; + goto CATCH; + } + + if (BackupDb(cert_db_journal_, cert_db_journal_bck) == -1) { + LOG(ERROR) << "Fail to backup [" << cert_db_journal_ << "] to [" << + cert_db_journal_bck << "]"; + goto CATCH; + } + + return 0; + +CATCH: + remove(parser_db_bck.c_str()); + remove(parser_db_journal_bck.c_str()); + remove(cert_db_bck.c_str()); + remove(cert_db_journal_bck.c_str()); + + return -1; +} + +void Upgrader::RemoveBackupPath(const string& origin_path) { + string backup_path = origin_path + ".bck"; + + if (remove(origin_path.c_str())) + LOG(ERROR) << "cannot remove backup file(" << backup_path << ") " << errno; +} + +void Upgrader::RemoveBackupDbs() { + RemoveBackupPath(parser_db_); + RemoveBackupPath(parser_db_journal_); + RemoveBackupPath(cert_db_); + RemoveBackupPath(cert_db_journal_); +} + +} // common_fota diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..c90fac8 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1 @@ +ADD_SUBDIRECTORY(unit_tests) diff --git a/tests/mock/mock_hook.h b/tests/mock/mock_hook.h new file mode 100644 index 0000000..79831d7 --- /dev/null +++ b/tests/mock/mock_hook.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MOCK_MOCK_HOOK_H_ +#define MOCK_MOCK_HOOK_H_ + +#define MOCK_HOOK_P0(MOCK_CLASS, f) \ + TestFixture::GetMock().f() +#define MOCK_HOOK_P1(MOCK_CLASS, f, p1) \ + TestFixture::GetMock().f(p1) +#define MOCK_HOOK_P2(MOCK_CLASS, f, p1, p2) \ + TestFixture::GetMock().f(p1, p2) +#define MOCK_HOOK_P3(MOCK_CLASS, f, p1, p2, p3) \ + TestFixture::GetMock().f(p1, p2, p3) +#define MOCK_HOOK_P4(MOCK_CLASS, f, p1, p2, p3, p4) \ + TestFixture::GetMock().f(p1, p2, p3, p4) +#define MOCK_HOOK_P5(MOCK_CLASS, f, p1, p2, p3, p4, p5) \ + TestFixture::GetMock().f(p1, p2, p3, p4, p5) +#define MOCK_HOOK_P6(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6) \ + TestFixture::GetMock().f(p1, p2, p3, p4, p5, p6) +#define MOCK_HOOK_P7(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7) \ + TestFixture::GetMock().f(p1, p2, p3, p4, p5, p6, p7) +#define MOCK_HOOK_P8(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7, p8) \ + TestFixture::GetMock().f(p1, p2, p3, p4, p5, p6, p7, p8) +#define MOCK_HOOK_P10(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \ + TestFixture::GetMock().f( \ + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) + +#endif // MOCK_MOCK_HOOK_H_ diff --git a/tests/mock/module_mock.h b/tests/mock/module_mock.h new file mode 100644 index 0000000..0934014 --- /dev/null +++ b/tests/mock/module_mock.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MOCK_MODULE_MOCK_H_ +#define MOCK_MODULE_MOCK_H_ + +class ModuleMock { + public: + virtual ~ModuleMock() {} +}; + +#endif // MOCK_MODULE_MOCK_H_ diff --git a/tests/mock/os_mock.cc b/tests/mock/os_mock.cc new file mode 100644 index 0000000..009f4ed --- /dev/null +++ b/tests/mock/os_mock.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "os_mock.h" +#include "mock_hook.h" +#include "test_fixture.h" + +extern "C" pid_t fork(void) { + return MOCK_HOOK_P0(OsMock, fork); +} + +extern "C" pid_t waitpid(pid_t pid, int *status, int options) { + return MOCK_HOOK_P3(OsMock, waitpid, pid, status, options); +} + +extern "C" int fchown(int fd, uid_t owner, gid_t group) { + return MOCK_HOOK_P3(OsMock, fchown, fd, owner, group); +} + +extern "C" int fchmod(int fd, mode_t mode) { + return MOCK_HOOK_P2(OsMock, fchmod, fd, mode); +} + +extern "C" int smack_setlabel(const char *path, const char* label, + enum smack_label_type type) { + return MOCK_HOOK_P3(OsMock, smack_setlabel, path, label, type); +} \ No newline at end of file diff --git a/tests/mock/os_mock.h b/tests/mock/os_mock.h new file mode 100644 index 0000000..64970b3 --- /dev/null +++ b/tests/mock/os_mock.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MOCK_OS_MOCK_H_ +#define MOCK_OS_MOCK_H_ + +#include +#include +#include +#include + +#include "module_mock.h" + +class OsMock : public virtual ModuleMock { + public: + virtual ~OsMock() {} + + MOCK_METHOD0(fork, pid_t()); + MOCK_METHOD3(waitpid, pid_t(pid_t, int*, int)); + MOCK_METHOD3(fchown, int(int, uid_t, gid_t)); + MOCK_METHOD2(fchmod, int(int, mode_t)); + MOCK_METHOD3(smack_setlabel, int(const char*, const char*, smack_label_type)); +}; + +#endif // MOCK_OS_MOCK_H_ diff --git a/tests/mock/pkgmgr_info_mock.cc b/tests/mock/pkgmgr_info_mock.cc new file mode 100644 index 0000000..2e0896b --- /dev/null +++ b/tests/mock/pkgmgr_info_mock.cc @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pkgmgr_info_mock.h" +#include "mock_hook.h" +#include "test_fixture.h" + +extern "C" int pkgmgrinfo_pkginfo_filter_create( + pkgmgrinfo_pkginfo_filter_h *handle) { + return MOCK_HOOK_P1(PkgMgrInfoMock, pkgmgrinfo_pkginfo_filter_create, handle); +} + +extern "C" int pkgmgrinfo_pkginfo_filter_destroy( + pkgmgrinfo_pkginfo_filter_h handle) { + return MOCK_HOOK_P1(PkgMgrInfoMock, pkgmgrinfo_pkginfo_filter_destroy, + handle); +} + +extern "C" int pkgmgrinfo_pkginfo_filter_add_bool( + pkgmgrinfo_pkginfo_filter_h handle, + const char *property, const bool value) { + return MOCK_HOOK_P3(PkgMgrInfoMock, pkgmgrinfo_pkginfo_filter_add_bool, + handle, property, value); +} + +extern "C" int pkgmgrinfo_pkginfo_filter_foreach_pkginfo( + pkgmgrinfo_pkginfo_filter_h handle, + pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data) { + return MOCK_HOOK_P3(PkgMgrInfoMock, pkgmgrinfo_pkginfo_filter_foreach_pkginfo, + handle, pkg_cb, user_data); +} + +extern "C" int pkgmgrinfo_pkginfo_get_pkgid(pkgmgrinfo_pkginfo_h handle, + char **pkgid) { + return MOCK_HOOK_P2(PkgMgrInfoMock, pkgmgrinfo_pkginfo_get_pkgid, + handle, pkgid); +} + +extern "C" int pkgmgrinfo_pkginfo_get_type(pkgmgrinfo_pkginfo_h handle, + char **type) { + return MOCK_HOOK_P2(PkgMgrInfoMock, pkgmgrinfo_pkginfo_get_type, + handle, type); +} + +extern "C" int pkgmgrinfo_pkginfo_get_version(pkgmgrinfo_pkginfo_h handle, + char **version) { + return MOCK_HOOK_P2(PkgMgrInfoMock, pkgmgrinfo_pkginfo_get_version, + handle, version); +} \ No newline at end of file diff --git a/tests/mock/pkgmgr_info_mock.h b/tests/mock/pkgmgr_info_mock.h new file mode 100644 index 0000000..2c4e47b --- /dev/null +++ b/tests/mock/pkgmgr_info_mock.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MOCK_PKGMGR_INFO_MOCK_H_ +#define MOCK_PKGMGR_INFO_MOCK_H_ + +#include +#include +#include + +#include "module_mock.h" + +class PkgMgrInfoMock : public virtual ModuleMock { + public: + virtual ~PkgMgrInfoMock() {} + + MOCK_METHOD1(pkgmgrinfo_pkginfo_filter_create, + int(pkgmgrinfo_pkginfo_filter_h*)); + MOCK_METHOD1(pkgmgrinfo_pkginfo_filter_destroy, + int(pkgmgrinfo_pkginfo_filter_h)); + MOCK_METHOD3(pkgmgrinfo_pkginfo_filter_add_bool, + int(pkgmgrinfo_pkginfo_filter_h, const char*, const bool)); + MOCK_METHOD3(pkgmgrinfo_pkginfo_filter_foreach_pkginfo, + int(pkgmgrinfo_pkginfo_filter_h, pkgmgrinfo_pkg_list_cb, void*)); + MOCK_METHOD2(pkgmgrinfo_pkginfo_get_pkgid, int(pkgmgrinfo_pkginfo_h, char**)); + MOCK_METHOD2(pkgmgrinfo_pkginfo_get_type, int(pkgmgrinfo_pkginfo_h, char**)); + MOCK_METHOD2(pkgmgrinfo_pkginfo_get_version, int(pkgmgrinfo_pkginfo_h, char**)); +}; + +#endif // MOCK_PKGMGR_INFO_MOCK_H_ diff --git a/tests/mock/test_fixture.cc b/tests/mock/test_fixture.cc new file mode 100644 index 0000000..27f5666 --- /dev/null +++ b/tests/mock/test_fixture.cc @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test_fixture.h" + +#include + +std::unique_ptr TestFixture::mock_; diff --git a/tests/mock/test_fixture.h b/tests/mock/test_fixture.h new file mode 100644 index 0000000..db223f1 --- /dev/null +++ b/tests/mock/test_fixture.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MOCK_TEST_FIXTURE_H_ +#define MOCK_TEST_FIXTURE_H_ + +#include + +#include +#include +#include +#include + +#include "module_mock.h" + +class TestFixture : public ::testing::Test { + public: + explicit TestFixture(std::unique_ptr&& mock) { + mock_ = std::move(mock); + } + virtual ~TestFixture() { + mock_.reset(); + } + + virtual void SetUp() {} + virtual void TearDown() {} + + template + static T& GetMock() { + auto ptr = dynamic_cast(mock_.get()); + if (!ptr) + throw std::invalid_argument("The test does not provide mock of \"" + + std::string(typeid(T).name()) + "\""); + return *ptr; + } + + static std::unique_ptr mock_; +}; + +#endif // MOCK_TEST_FIXTURE_H_ diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt new file mode 100644 index 0000000..b946e29 --- /dev/null +++ b/tests/unit_tests/CMakeLists.txt @@ -0,0 +1,45 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +PROJECT(pkgmgr-tool_unittests C CXX) + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(pkgmgr-tool_unittests REQUIRED + dlog + gmock + pkgmgr-parser + pkgmgr-info + libtzplatform-config + libsmack +) + +FOREACH(flag ${pkgmgr-tool_unittests_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -fPIE") + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++14") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_CXX_FLAGS_RELEASE "-O2") + +ADD_DEFINITIONS("-DDB_PATH=\"${DB_PATH}\"") + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../../src/pkg_upgrade/include) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../mock) + +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SOURCES) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../../src/pkg_upgrade/src LIB_SOURCES) +LIST(REMOVE_ITEM LIB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../src/pkg_upgrade/src/main.cc) +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../mock MOCK_SOURCES) + +ADD_EXECUTABLE(${PROJECT_NAME} + ${SOURCES} + ${MOCK_SOURCES} + ${LIB_SOURCES} +) + +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}") +TARGET_LINK_LIBRARIES(${PROJECT_NAME} + ${pkgmgr-tool_unittests_LDFLAGS} +) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin/) +INSTALL(DIRECTORY data/ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/data) \ No newline at end of file diff --git a/tests/unit_tests/data/db/.pkgmgr_cert.db b/tests/unit_tests/data/db/.pkgmgr_cert.db new file mode 100644 index 0000000..86d5ef2 Binary files /dev/null and b/tests/unit_tests/data/db/.pkgmgr_cert.db differ diff --git a/tests/unit_tests/data/db/.pkgmgr_cert.db-journal b/tests/unit_tests/data/db/.pkgmgr_cert.db-journal new file mode 100644 index 0000000..a79929d Binary files /dev/null and b/tests/unit_tests/data/db/.pkgmgr_cert.db-journal differ diff --git a/tests/unit_tests/data/db/.pkgmgr_parser.db b/tests/unit_tests/data/db/.pkgmgr_parser.db new file mode 100644 index 0000000..95bb964 Binary files /dev/null and b/tests/unit_tests/data/db/.pkgmgr_parser.db differ diff --git a/tests/unit_tests/data/db/.pkgmgr_parser.db-journal b/tests/unit_tests/data/db/.pkgmgr_parser.db-journal new file mode 100644 index 0000000..b20e4d3 Binary files /dev/null and b/tests/unit_tests/data/db/.pkgmgr_parser.db-journal differ diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_cert.db b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db new file mode 100644 index 0000000..86d5ef2 Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db differ diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal new file mode 100644 index 0000000..a79929d Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal differ diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal.bck b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal.bck new file mode 100644 index 0000000..a79929d Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db-journal.bck differ diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_cert.db.bck b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db.bck new file mode 100644 index 0000000..86d5ef2 Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_cert.db.bck differ diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_parser.db b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db new file mode 100644 index 0000000..95bb964 Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db differ diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal new file mode 100644 index 0000000..b20e4d3 Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal differ diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal.bck b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal.bck new file mode 100644 index 0000000..b20e4d3 Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db-journal.bck differ diff --git a/tests/unit_tests/data/db_bck/.pkgmgr_parser.db.bck b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db.bck new file mode 100644 index 0000000..95bb964 Binary files /dev/null and b/tests/unit_tests/data/db_bck/.pkgmgr_parser.db.bck differ diff --git a/tests/unit_tests/data/packages/org.tizen.alarm.xml b/tests/unit_tests/data/packages/org.tizen.alarm.xml new file mode 100644 index 0000000..39e4cad --- /dev/null +++ b/tests/unit_tests/data/packages/org.tizen.alarm.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.tizen.alarm.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.tizen.alarm.png + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.tizen.alarm.png + + + http://tizen.org/privilege/haptic + http://tizen.org/privilege/datasharing + http://tizen.org/privilege/display + http://tizen.org/privilege/appmanager.launch + http://tizen.org/privilege/alarm.get + http://tizen.org/privilege/alarm.set + + + + org.tizen.alarm.png + + + + + org.tizen.alarm.png + 2x2 + + diff --git a/tests/unit_tests/data/packages/org.tizen.app-selector.xml b/tests/unit_tests/data/packages/org.tizen.app-selector.xml new file mode 100644 index 0000000..314cff5 --- /dev/null +++ b/tests/unit_tests/data/packages/org.tizen.app-selector.xml @@ -0,0 +1,13 @@ + + + + Application Selection Popup + + + + + http://tizen.org/privilege/appmanager.launch + http://tizen.org/privilege/mediastorage + http://tizen.org/privilege/externalstorage + + diff --git a/tests/unit_tests/data/packages/org.tizen.bluetooth.xml b/tests/unit_tests/data/packages/org.tizen.bluetooth.xml new file mode 100644 index 0000000..b3f618e --- /dev/null +++ b/tests/unit_tests/data/packages/org.tizen.bluetooth.xml @@ -0,0 +1,20 @@ + + + + Insung Cho + W bluetooth + + + + + + + + + + + + http://tizen.org/privilege/bluetooth + http://tizen.org/privilege/bluetooth.admin + + diff --git a/tests/unit_tests/data/rw/list.txt b/tests/unit_tests/data/rw/list.txt new file mode 100644 index 0000000..eaba1da --- /dev/null +++ b/tests/unit_tests/data/rw/list.txt @@ -0,0 +1,2 @@ +"package=org.tizen.new_rw":"version=1.2.0":"type=tpk":"removable=false" +"package=org.test.pkg2":"version=1.2.0":"type=wgt":"removable=true" diff --git a/tests/unit_tests/src/test_main.cc b/tests/unit_tests/src/test_main.cc new file mode 100644 index 0000000..c2eb730 --- /dev/null +++ b/tests/unit_tests/src/test_main.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +int main(int argc, char** argv) { + int ret = -1; + + try { + testing::InitGoogleTest(&argc, argv); + } catch(...) { + std::cout << "Exception occurred" << std::endl; + } + + try { + ret = RUN_ALL_TESTS(); + } catch (const ::testing::internal::GoogleTestFailureException& e) { + ret = -1; + std::cout << "GoogleTestFailureException was thrown:" << e.what() << std::endl; + } + + return ret; +} diff --git a/tests/unit_tests/src/test_pkg_upgrader.cc b/tests/unit_tests/src/test_pkg_upgrader.cc new file mode 100644 index 0000000..1a13125 --- /dev/null +++ b/tests/unit_tests/src/test_pkg_upgrader.cc @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "pkgmgr_info_mock.h" +#include "os_mock.h" +#include "test_fixture.h" +#include "pkg_finder.hh" +#include "pkg_upgrader_factory.hh" +#include "upgrader.hh" + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::InvokeArgument; +using ::testing::SaveArg; + +using namespace common_fota; + +class Mocks : public ::testing::NiceMock, + public ::testing::NiceMock {}; + +class PkgFinderTest : public TestFixture { + public: + PkgFinderTest() : TestFixture(std::make_unique()) {} + virtual ~PkgFinderTest() {} + + virtual void SetUp() { + static int k; + pkgmgrinfo_pkginfo_filter_h dummy_filter = (pkgmgrinfo_pkginfo_filter_h)&k; + + EXPECT_CALL(GetMock(), pkgmgrinfo_pkginfo_filter_create(_)) + .WillRepeatedly(DoAll(SetArgPointee<0>(dummy_filter), Return(0))); + EXPECT_CALL(GetMock(), + pkgmgrinfo_pkginfo_filter_add_bool(_, _, _)) + .WillRepeatedly(Return(0)); + + EXPECT_CALL(GetMock(), + pkgmgrinfo_pkginfo_filter_foreach_pkginfo(_, _, _)) + .WillOnce( + Invoke([](pkgmgrinfo_pkginfo_filter_h handle, + pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data) -> int { + pkg_cb(nullptr, user_data); + pkg_cb(nullptr, user_data); + pkg_cb(nullptr, user_data); + return 0; + }) + ) + .WillOnce(Invoke([](pkgmgrinfo_pkginfo_filter_h handle, + pkgmgrinfo_pkg_list_cb pkg_cb, void *user_data) -> int { + pkg_cb(nullptr, user_data); + return 0; + })); + + const char* old_ro_pkgid[] = { + "org.test.pkg1", + "org.test.pkg2", + "org.tizen.app-selector" + }; + + const char* old_ro_pkg_type[] = { + "tpk", + "wgt", + "tpk" + }; + + const char* old_ro_pkg_version[] = { + "1.0.0", + "1.2.0", + "0.1.0" + }; + + const char* old_rw_pkgid[] = { + "org.tizen.alarm" + }; + + const char* old_rw_pkg_type[] = { + "tpk" + }; + + const char* old_rw_pkg_version[] = { + "1.5.0", + }; + + EXPECT_CALL(GetMock(), + pkgmgrinfo_pkginfo_get_pkgid(_,_)) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkgid[0])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkgid[1])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkgid[2])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_rw_pkgid[0])), Return(0))); + EXPECT_CALL(GetMock(), + pkgmgrinfo_pkginfo_get_type(_,_)) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkg_type[0])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkg_type[1])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkg_type[2])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_rw_pkg_type[0])), Return(0))); + EXPECT_CALL(GetMock(), + pkgmgrinfo_pkginfo_get_version(_,_)) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkg_version[0])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkg_version[1])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_ro_pkg_version[2])), Return(0))) + .WillOnce(DoAll(SetArgPointee<1>(const_cast(old_rw_pkg_version[0])), Return(0))); + + EXPECT_CALL(GetMock(), pkgmgrinfo_pkginfo_filter_destroy(_)) + .WillRepeatedly(Return(0)); + + finder_.SetManifestDir("./tests/unit_tests/data/packages/"); + finder_.SetPreloadRwListPath("./tests/unit_tests/data/rw/list.txt"); + } + + virtual void TearDown() { + } + + PkgFinder finder_; +}; + +TEST_F(PkgFinderTest, PkgFinder) { + finder_.Find(); + + EXPECT_EQ(finder_.GetOldPkgs().size(), 4); + EXPECT_EQ(finder_.GetNewPkgs().size(), 5); +} + +TEST_F(PkgFinderTest, PkgUpgraderFactory) { + PkgUpgraderFactory factory; + auto list = factory.MakeList(&finder_); + + EXPECT_EQ(list.size(), 6); +} + +class PkgUpgraderTest : public PkgFinderTest { + public: + PkgUpgraderTest() {} + virtual ~PkgUpgraderTest() {} + + void SetUp() override { + PkgFinderTest::SetUp(); + EXPECT_CALL(GetMock(), fork()) + .WillRepeatedly(Return(1)); + EXPECT_CALL(GetMock(), waitpid(_, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(1))); + EXPECT_CALL(GetMock(), fchown(_, _, _)) + .WillRepeatedly(Return(0)); + EXPECT_CALL(GetMock(), fchmod(_, _)) + .WillRepeatedly(Return(0)); + EXPECT_CALL(GetMock(), smack_setlabel(_, _, _)) + .WillRepeatedly(Return(0)); + } + + void TearDown() override { + PkgFinderTest::TearDown(); + } +}; + +TEST_F(PkgUpgraderTest, Upgrader) { + Upgrader upgrader; + + upgrader.SetDbPath("./tests/unit_tests/data/db"); + ASSERT_TRUE(upgrader.Process(&finder_)); + + const auto& success = upgrader.GetSuccessList(); + const auto& failure = upgrader.GetFailureList(); + + EXPECT_EQ(success.size(), 6); + EXPECT_EQ(failure.size(), 0); +} + +TEST_F(PkgUpgraderTest, Upgrader_db_bck) { + Upgrader upgrader; + + upgrader.SetDbPath("./tests/unit_tests/data/db_bck"); + EXPECT_TRUE(upgrader.Process(&finder_)); +} + +class PkgUpgraderTestForInvalidDbPath : public TestFixture { + public: + PkgUpgraderTestForInvalidDbPath() : TestFixture(std::make_unique()) {} + virtual ~PkgUpgraderTestForInvalidDbPath() {} + + virtual void SetUp() { + finder_.SetManifestDir("./tests/unit_tests/data/packages/"); + finder_.SetPreloadRwListPath("./tests/unit_tests/data/rw/list.txt"); + } + + virtual void TearDown() { + } + + PkgFinder finder_; +}; + +TEST_F(PkgUpgraderTestForInvalidDbPath, Upgrader_invalid_db) { + Upgrader upgrader; + + upgrader.SetDbPath("./tests/unit_tests/data/invalid_path"); + EXPECT_FALSE(upgrader.Process(&finder_)); +}