SET(PREFIX ${CMAKE_INSTALL_PREFIX})
ADD_SUBDIRECTORY(src/libisu)
ADD_SUBDIRECTORY(src/isud)
+ADD_SUBDIRECTORY(src/pkg_manager)
+ADD_SUBDIRECTORY(src/plugin_parser)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(mount)
BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(libxml-2.0)
+BuildRequires: pkgconfig(pkgmgr-info)
%description
Individual Service Upgrade is Tizen mechanism used to allow extending
Summary: Package provides headers needed to develop programs using ISU API
%description -n libisu-devel
+%package -n isu-plugin-parser
+Summary: Package provides package manager parser plugin to install ISU packages.
+%description -n isu-plugin-parser
+
%prep
%setup -q
%{_includedir}/libisu.h
%{_includedir}/libisu-internal.h
%{_libdir}/pkgconfig/*.pc
+
+
+%files -n isu-plugin-parser
+%manifest isu.manifest
+%license LICENSE.MIT
+/etc/package-manager/parserlib/libisu-parser.so*
+/usr/share/parser-plugins/isu-parser.info
#define TIMEOUT_INTERVAL_SEC 30
+enum Action {
+ Install,
+ InstallDir,
+ Uninstall,
+};
+
static GMainLoop *loop;
static GMutex timeout_mutex;
static guint timeout_id;
" <arg type='s' name='path' direction='in'/>"
" <arg type='i' name='result' direction='out'/>"
" </method>"
+" <method name='install_dir'>"
+" <arg type='s' name='path' direction='in'/>"
+" <arg type='i' name='result' direction='out'/>"
+" </method>"
" <method name='uninstall'>"
" <arg type='s' name='name' direction='in'/>"
" <arg type='i' name='result' direction='out'/>"
SLOGD("Remove loop timeout");
}
-static void call_handler(GDBusMethodInvocation *invocation, bool install)
+static char* action2str(enum Action action) {
+ switch (action) {
+ case Install:
+ return "install";
+ case InstallDir:
+ return "install dir";
+ case Uninstall:
+ return "uninstall";
+ }
+ return "unknown action";
+}
+
+static void call_handler(GDBusMethodInvocation *invocation, enum Action action)
{
GDBusMessage *incoming_message = g_dbus_method_invocation_get_message(invocation);
GVariant *body = g_dbus_message_get_body(incoming_message);
gchar *data;
g_variant_get(body, "(s)", &data);
int res;
- if (install) {
- res = isu_install_internal(data);
- } else {
- res = isu_uninstall_internal(data);
+ switch (action) {
+ case Install:
+ res = isu_install_internal(data);
+ break;
+ case InstallDir:
+ res = isu_install_dir_internal(data);
+ break;
+ case Uninstall:
+ res = isu_uninstall_internal(data);
+ break;
+ default:
+ res = -1;
}
SLOGD("ISU Package \"%s\" %s %s (%d)", data,
- install ? "installation" : "uninstallation",
+ action2str(action),
res == ISU_RES_OK ? "success" : "error",
res);
g_dbus_method_invocation_return_value(invocation,
static void install_handler(GDBusMethodInvocation *invocation)
{
- call_handler(invocation, true);
+ call_handler(invocation, Install);
+}
+
+static void install_dir_handler(GDBusMethodInvocation *invocation)
+{
+ call_handler(invocation, InstallDir);
}
static void uninstall_handler(GDBusMethodInvocation *invocation)
{
- call_handler(invocation, false);
+ call_handler(invocation, Uninstall);
}
static void method_call_handler(GDBusConnection *conn,
remove_timeout();
if (g_strcmp0(method_name, "install") == 0) {
- SLOGD("Install");
install_handler(invocation);
+ } else if (g_strcmp0(method_name, "install_dir") == 0) {
+ install_dir_handler(invocation);
} else if (g_strcmp0(method_name, "uninstall") == 0) {
- SLOGD("Uninstall");
uninstall_handler(invocation);
} else {
SLOGE("Unsupported method: %s", method_name);
#include <assert.h>
#include <archive_entry.h>
#include <archive.h>
+#include <errno.h>
#include <dlog/dlog.h>
#include <limits.h>
#include <stdlib.h>
#include <system_info.h>
#include <libmount.h>
#include <gio/gio.h>
+#include <fcntl.h>
+#include <sys/sendfile.h>
#include "libisu-internal.h"
// Arbitrarily determined block size
#define CFG_NAME "name"
#define CFG_VERSION "version"
#define CFG_SYSTEM_SERVICE "system_service"
+#define DBUS_METHOD_INSTALL_DIR "install_dir"
+#define AUTHOR_SIGNATURE_FILE "author-signature.xml"
+#define SIGNATURE_FILE "signature1.xml"
+#define TIZEN_MANIFEST_FILE "tizen-manifest.xml"
+
bool is_isu_feature_supported()
{
return feature_res;
}
+static int copy_content(const char *src, const char *dst, const char **exclude)
+{
+ int result = -1;
+ DIR *dir;
+ struct dirent *entry;
+ dir = opendir(src);
+ if (dir == NULL) {
+ SLOGE("Cannot open directory %s: (%d) %m", src, errno);
+ return -1;
+ }
+ while ((entry = readdir(dir)) != NULL) {
+ bool ignore = false;
+
+ if (exclude != NULL) {
+ // I assume that the exclude[] will contain few elements.
+ for(size_t i = 0; exclude[i] != NULL; i++) {
+ if (strcmp(entry->d_name, exclude[i]) == 0) {
+ ignore = true;
+ break;
+ }
+ }
+ }
+
+ if (ignore ||
+ strncmp(entry->d_name, ".", 2) == 0 ||
+ strncmp(entry->d_name, "..", 3) == 0) {
+ continue;
+ }
+
+ char newsrc[PATH_MAX];
+ char newdst[PATH_MAX];
+ snprintf(newsrc, sizeof(newsrc), "%s/%s", src, entry->d_name);
+ snprintf(newdst, sizeof(newdst),"%s/%s", dst, entry->d_name);
+
+ int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ if (entry->d_type == DT_DIR) {
+ if (mkdir(newdst, mode | S_IXUSR | S_IXOTH) == -1 && errno != EEXIST) {
+ SLOGE("Make directory %s error: (%d) %m", newdst, errno);
+ goto exit;
+ }
+ if (copy_content(newsrc, newdst, exclude) != 0) {
+ goto exit;
+ }
+ } else if (entry->d_type == DT_REG) {
+ int src_file = open(newsrc, O_RDONLY);
+ int dst_file = open(newdst, O_CREAT | O_WRONLY, mode);
+ if (src_file == -1 || dst_file == -1) {
+ if (src_file == -1)
+ SLOGE("Cannot open file %s: (%d) %m", newsrc, errno);
+ if (dst_file == -1)
+ SLOGE("Cannot open file %s: (%d) %m", newdst, errno);
+ goto exit;
+ }
+ struct stat fileinfo = {0};
+ if (fstat(src_file, &fileinfo) == -1) {
+ SLOGE("Get file %s status error: (%d) %m", newsrc, errno);
+ }
+
+ if (sendfile(dst_file, src_file, NULL, fileinfo.st_size) == -1) {
+ SLOGE("Copy file content (%s -> %s) error: (%d) %m", newsrc, newdst, errno);
+ goto exit;
+ }
+ }
+ }
+ result = 0;
+exit:
+ closedir(dir);
+ return result;
+}
+
isu_result isu_dbus_call(const char *method, const char *parameter)
{
GError *error = NULL;
return pkg_info;
}
+isu_result isu_install_dir_internal(const char *path)
+{
+ char isucfg_path[PATH_MAX];
+ snprintf(isucfg_path, sizeof(isucfg_path), "%s/%s", path, ISU_CFG);
+ struct _isu_pkg_info *pkg_info = get_pkg_info(isucfg_path);
+ if (pkg_info == NULL) {
+ return ISU_RES_ERR_INTERNAL;
+ }
+ char dst_path[PATH_MAX];
+ snprintf(dst_path, sizeof(dst_path), "%s/%s", ISU_PKG_PATH, pkg_info->name);
+ isu_pkg_info_free(pkg_info);
+
+ const char *exclude[] = {AUTHOR_SIGNATURE_FILE,
+ SIGNATURE_FILE,
+ TIZEN_MANIFEST_FILE,
+ NULL};
+
+ if (mkdir(dst_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
+ errno != EEXIST) {
+ SLOGE("Create directory %s error: (%d) %m", dst_path, errno);
+ return ISU_RES_ERR_INTERNAL;
+ }
+ if (copy_content(path, dst_path, exclude) != 0) {
+ return ISU_RES_ERR_INTERNAL;
+ }
+ return ISU_RES_OK;
+}
+
isu_result isu_install_internal(const char *path)
{
RET_IF_FEATURE_NOT_SUPPORTED(ISU_RES_ERR_FEATURE);
return ISU_FILE_RES_IS_NORMAL_FILE;
}
+isu_result isu_install_dir(const char *path)
+{
+ RET_IF_FEATURE_NOT_SUPPORTED(ISU_RES_ERR_FEATURE);
+
+ if (path == NULL)
+ return ISU_RES_ERR_ARGUMENT;
+
+ return isu_dbus_call(DBUS_METHOD_INSTALL_DIR, path);
+}
+
char **service_files;
};
+isu_result isu_install_dir(const char *path);
+isu_result isu_install_dir_internal(const char *path);
isu_result isu_install_internal(const char *path);
isu_result isu_uninstall_internal(const char *name);
isu_file_res is_isu_file(const char *path, pid_t pid, char **source_path);
struct _isu_pkg_info* get_pkg_info(const char *isu_cfg_path);
+isu_result isu_dbus_call(const char *method, const char *parameter);
--- /dev/null
+PROJECT(isu-parser C)
+FIND_PACKAGE(PkgConfig)
+INCLUDE(GNUInstallDirs)
+
+pkg_check_modules(deps REQUIRED
+ dlog
+ capi-system-info
+ libxml-2.0
+ )
+
+ADD_LIBRARY(isu-parser SHARED isu-parser.c)
+SET_TARGET_PROPERTIES(isu-parser PROPERTIES VERSION ${LIBISU_VERSION})
+SET_TARGET_PROPERTIES(isu-parser PROPERTIES SOVERSION 1)
+TARGET_COMPILE_OPTIONS(isu-parser PUBLIC -fPIC)
+TARGET_INCLUDE_DIRECTORIES(isu-parser PRIVATE . ${deps_INCLUDE_DIRS} ../libisu/)
+TARGET_LINK_LIBRARIES(isu-parser PRIVATE isu ${deps_LDFLAGS})
+
+INSTALL(TARGETS isu-parser LIBRARY DESTINATION /etc/package-manager/parserlib/)
+INSTALL(FILES isu-parser.info DESTINATION /usr/share/parser-plugins/)
+
--- /dev/null
+#include <stdio.h>
+#include <dlog.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <pkgmgr-info.h>
+#include "libisu.h"
+#include "libisu-internal.h"
+
+#ifndef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+#ifdef LOG_TAG
+ #undef LOG_TAG
+#endif
+#define LOG_TAG "ISU_PARSER"
+
+
+int install_package(const char* packageId) {
+ pkgmgrinfo_pkginfo_h handle;
+ int result = -1;
+ int res = pkgmgrinfo_pkginfo_get_pkginfo(packageId, &handle);
+ if (res != PMINFO_R_OK) {
+ SLOGE("[%d] Cannot get pkginfo for %s", res, packageId);
+ return -1;
+ }
+
+ char *path;
+ res = pkgmgrinfo_pkginfo_get_root_path(handle, &path);
+ if (res != PMINFO_R_OK) {
+ SLOGE("[%d] Cannot get root path for %s", res, packageId);
+ goto exit;
+ }
+
+ res = isu_install_dir(path);
+ if (res == 0) {
+ SLOGE("ISU package (%s) install success", packageId);
+ } else {
+ SLOGE("[%d] ISU package (%s) install error", res, packageId);
+ goto exit;
+ }
+ result = 0;
+
+exit:
+ pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+ return result;
+}
+
+int uninstall_package(const char* packageId) {
+ pkgmgrinfo_pkginfo_h handle;
+ int result = -1;
+ int res = pkgmgrinfo_pkginfo_get_pkginfo(packageId, &handle);
+ if (res != PMINFO_R_OK) {
+ SLOGE("[%d] Cannot get pkginfo for %s", res, packageId);
+ return -1;
+ }
+
+ char *path;
+ struct _isu_pkg_info *pkg_info = NULL;
+ res = pkgmgrinfo_pkginfo_get_root_path(handle, &path);
+ if (res != PMINFO_R_OK) {
+ SLOGE("[%d] Cannot get root path for %s", res, packageId);
+ goto exit;
+ }
+
+ char isu_cfg_path[PATH_MAX];
+ snprintf(isu_cfg_path, sizeof(isu_cfg_path), "%s/%s", path, ISU_CFG);
+ pkg_info = get_pkg_info(isu_cfg_path);
+ if (pkg_info == NULL) {
+ SLOGE("Get package info error");
+ goto exit;
+ }
+ res = isu_uninstall(pkg_info->name);
+
+ if (res == 0) {
+ SLOGD("ISU Package (%s) uninstall success", packageId);
+ } else {
+ SLOGE("[%d] ISU package (%s) uninstall error", res, packageId);
+ goto exit;
+ }
+ result = 0;
+exit:
+ if (pkg_info != NULL)
+ isu_pkg_info_free(pkg_info);
+ pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+
+ return result;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_PRE_INSTALL(const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr docPtr, const char* packageId)
+{
+ SLOGD("Install ISU Package: %s", packageId);
+ return install_package(packageId);
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_POST_INSTALL(const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr docPtr, const char* packageId)
+{
+ return uninstall_package(packageId);
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_PRE_UNINSTALL(const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_POST_UNINSTALL(const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_PRE_UPGRADE(const char* packageId)
+{
+ return 0;
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr docPtr, const char* packageId)
+{
+ SLOGD("Upgrade ISU Pacakge: %s", packageId);
+ return install_package(packageId);
+}
+
+EXPORT_API
+int PKGMGR_PARSER_PLUGIN_POST_UPGRADE(const char* packageId)
+{
+ return 0;
+}
--- /dev/null
+type="tag";name="isu";path="/etc/package-manager/parserlib/libisu-parser.so"