Add a new ISU package manager 27/299627/19
authorMateusz Moscicki <m.moscicki2@partner.samsung.com>
Tue, 24 Oct 2023 10:36:59 +0000 (12:36 +0200)
committerMateusz Moscicki <m.moscicki2@partner.samsung.com>
Fri, 1 Dec 2023 12:29:38 +0000 (13:29 +0100)
Change-Id: I5c10d71bbc9fcf8d0ae89fd6aa43b049e1fda723

packaging/isu.spec
src/isud/CMakeLists.txt
src/pkg_manager/CMakeLists.txt [new file with mode: 0644]
src/pkg_manager/isu.c [new file with mode: 0644]

index 361bc6a..475fb29 100644 (file)
@@ -56,7 +56,7 @@ install -m644 -D src/helpers/service-common.inc %{buildroot}/etc/isu/service-com
 install -m644 -D src/helpers/user-service-common.inc %{buildroot}/etc/isu/user-service-common.inc
 install -m644 config/isu.conf %{buildroot}/usr/lib/tmpfiles.d/isu.conf
 install -m644 config/upgrade.cfg %{buildroot}/etc/isu/upgrade.cfg
-install -m750 src/pkg_manager/isu %{buildroot}/%{_bindir}/isu
+install -m750 src/pkg_manager/isu %{buildroot}/%{_bindir}/isu.sh
 
 %files
 %manifest isu.manifest
@@ -68,6 +68,7 @@ install -m750 src/pkg_manager/isu %{buildroot}/%{_bindir}/isu
 /etc/isu/service-common.inc
 /etc/isu/user-service-common.inc
 /etc/isu/upgrade.cfg
+%{_bindir}/isu.sh
 %{_bindir}/isu
 
 %files -n libisu
index 51904a3..bfc10b4 100644 (file)
@@ -10,7 +10,7 @@ pkg_check_modules(deps REQUIRED
 
 
 ADD_EXECUTABLE(isud isud.c)
-TARGET_COMPILE_OPTIONS(isud PRIVATE ${deps_CFLAGS_OTHER} -fPIC)
+TARGET_COMPILE_OPTIONS(isud PRIVATE ${deps_CFLAGS_OTHER} -fPIE)
 TARGET_INCLUDE_DIRECTORIES(isud PRIVATE ${deps_INCLUDE_DIRS} ../libisu/)
 TARGET_LINK_LIBRARIES(isud PRIVATE isu ${deps_LDFLAGS} -pie -larchive)
 
diff --git a/src/pkg_manager/CMakeLists.txt b/src/pkg_manager/CMakeLists.txt
new file mode 100644 (file)
index 0000000..96d9f48
--- /dev/null
@@ -0,0 +1,10 @@
+INCLUDE(GNUInstallDirs)
+FIND_PACKAGE(PkgConfig)
+pkg_check_modules(deps REQUIRED "glib-2.0 gio-2.0 capi-system-info dlog")
+
+ADD_EXECUTABLE(isu_manager isu.c)
+SET_TARGET_PROPERTIES(isu_manager PROPERTIES OUTPUT_NAME "isu")
+TARGET_INCLUDE_DIRECTORIES(isu_manager PRIVATE . ${deps_INCLUDE_DIRS} ../libisu/)
+TARGET_LINK_LIBRARIES(isu_manager PUBLIC isu -pie -larchive ${deps_LIBRARIES})
+
+INSTALL(TARGETS isu_manager DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/pkg_manager/isu.c b/src/pkg_manager/isu.c
new file mode 100644 (file)
index 0000000..3471e77
--- /dev/null
@@ -0,0 +1,346 @@
+#include <assert.h>
+#include <dirent.h>
+#include <gio/gio.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlog/dlog.h>
+
+#include "libisu-internal.h"
+
+static char *err2str(int error)
+{
+    switch (error) {
+        case ISU_RES_OK:
+            return "OK";
+        case ISU_RES_ERR_NAME:
+            return "Invalid name";
+        case ISU_RES_ERR_NOT_EXIST:
+            return "ISU package not exist";
+        case ISU_RES_ERR_PATH:
+            return "Provided file not exist";
+        case ISU_RES_ERR_INVALID_FORMAT:
+            return "Incorrect or corrupted ISU package";
+        case ISU_RES_ERR_INTERNAL:
+            return "Internal error";
+        case ISU_RES_ERR_FEATURE:
+            return "Feature ISU is not supported";
+        case ISU_RES_ERR_CHECKSUM:
+            return "Checksum of the ISU packagge is incorrect";
+        case ISU_RES_ERR_NOT_PERMITTED:
+            return "Permission denied";
+    }
+    return NULL;
+}
+
+static int install_isu(const char *path)
+{
+    assert(path);
+
+    int res = isu_install(path);
+    if (res == ISU_RES_OK) {
+            fprintf(stderr, "Installation success\n");
+    } else {
+            fprintf(stderr, "Installation error: %s\n", err2str(res));
+    }
+    return res;
+}
+
+static int uninstall_isu(const char *name)
+{
+    assert(name);
+
+    int res = isu_uninstall(name);
+    if (res == ISU_RES_OK) {
+        printf("Uninstallation success\n");
+    } else {
+        printf("Uninstallation error: %s\n", err2str(res));
+    }
+    return res;
+}
+
+static char *get_unit_name(GDBusConnection *conn, const char *service_file)
+{
+    assert(conn);
+    assert(service_file);
+
+    GError *err = NULL;
+    GVariant *ret = g_dbus_connection_call_sync(conn,
+                                                "org.freedesktop.systemd1",
+                                                "/org/freedesktop/systemd1",
+                                                "org.freedesktop.systemd1.Manager",
+                                                "GetUnit",
+                                                g_variant_new("(s)", service_file),
+                                                G_VARIANT_TYPE("(o)"),
+                                                G_DBUS_CALL_FLAGS_NONE,
+                                                -1,
+                                                NULL,
+                                                &err);
+    if (err != NULL) {
+        fprintf(stderr, "Error: %s\n", err->message);
+        g_error_free(err);
+    }
+
+    if (ret == NULL) {
+        return NULL;
+    }
+
+    char *unit_name;
+    g_variant_get(ret, "(&o)", &unit_name);
+    char *result = strdup(unit_name);
+    g_variant_unref(ret);
+    return result;
+}
+
+static char *get_dbus_property(GDBusConnection *conn, const char *unit_name, const char *property_name)
+{
+    assert(conn);
+    assert(unit_name);
+    assert(property_name);
+
+    GError *err = NULL;
+    GVariant *ret = g_dbus_connection_call_sync(conn,
+                                                "org.freedesktop.systemd1",
+                                                unit_name,
+                                                "org.freedesktop.DBus.Properties",
+                                                "Get",
+                                                g_variant_new("(ss)", "org.freedesktop.systemd1.Unit", property_name),
+                                                G_VARIANT_TYPE("(v)"),
+                                                G_DBUS_CALL_FLAGS_NONE,
+                                                -1,
+                                                NULL,
+                                                &err);
+
+    if (err != NULL) {
+        fprintf(stderr, "Error: %s\n", err->message);
+        g_error_free(err);
+    }
+    if (ret == NULL) {
+        return NULL;
+    }
+
+    GVariant *v;
+    g_variant_get(ret, "(v)", &v);
+    if (v == NULL) {
+        return NULL;
+    }
+
+    char *value;
+    g_variant_get(v, "s", &value);
+    g_variant_unref(v);
+    g_variant_unref(ret);
+    return value;
+}
+
+static char *get_fragment_path(GDBusConnection *conn, const char *unit_name)
+{
+    assert(conn);
+    assert(unit_name);
+    return get_dbus_property(conn, unit_name, "FragmentPath");
+}
+
+static char *get_service_status(GDBusConnection *conn, const char *unit_name)
+{
+    assert(conn);
+    assert(unit_name);
+    return get_dbus_property(conn, unit_name, "SubState");
+}
+
+#define FREE_AND_NULL_IF_NOT_NULL(v) \
+        if (v != NULL) { \
+            free(v); \
+            v = NULL; \
+} \
+
+static bool print_status_for_package(GDBusConnection *conn, struct _isu_pkg_list_element *pkg)
+{
+    assert(conn);
+    assert(pkg);
+
+    char buff[PATH_MAX];
+    snprintf(buff, sizeof(buff), "%s/%s/isu.cfg", ISU_RUN_PATH, pkg->name);
+    struct _isu_pkg_info *info = get_pkg_info(buff);
+
+    if (info == NULL) {
+        return false;
+    }
+
+    char *unit_name = NULL;
+    char *fragment_path = NULL;
+    char *status = NULL;
+
+    for (size_t i = 0; i < info->service_files_len; i++) {
+        char *service_file = info->service_files[i];
+        if (service_file == NULL) {
+            fprintf(stderr, "Can not get service file for package %s\n", info->name);
+            return false;
+        }
+        FREE_AND_NULL_IF_NOT_NULL(unit_name)
+        FREE_AND_NULL_IF_NOT_NULL(fragment_path)
+        FREE_AND_NULL_IF_NOT_NULL(status)
+
+        unit_name = get_unit_name(conn, service_file);
+        if (unit_name == NULL) {
+            continue;
+        }
+
+        fragment_path = get_fragment_path(conn, unit_name);
+        if (fragment_path == NULL) {
+            continue;
+        }
+
+        status = get_service_status(conn, unit_name);
+        if (status == NULL) {
+            continue;
+        }
+
+        printf("%s (%s) [%s] %s\n", info->name, info->version, service_file, status);
+    }
+
+    free(unit_name);
+    free(fragment_path);
+    free(status);
+    isu_pkg_info_free(info);
+
+    return true;
+}
+
+struct _isu_pkg_list *get_running_pkgs()
+{
+    return (struct _isu_pkg_list*)isu_list_init();;
+}
+
+struct _isu_pkg_list *get_pkgs_from_argv(char **argv, int argc)
+{
+    assert(argv);
+
+    struct _isu_pkg_list *list = malloc(sizeof(struct _isu_pkg_list));
+    list->cur = NULL;
+    list->head = NULL;
+
+    for (size_t i = 2; i < argc; i++) {
+        struct _isu_pkg_list_element *element = malloc(sizeof(struct _isu_pkg_list_element));
+        element->name = strdup(argv[i]);
+        element->next = NULL;
+
+        if (list->head == NULL) {
+            list->head = element;
+        } else {
+            list->cur->next = element;
+        }
+        list->cur = element;
+    }
+    list->cur = list->head;
+
+    return list;
+}
+
+static int print_status(struct _isu_pkg_list *pkg_list)
+{
+    assert(pkg_list);
+
+    GError *err = NULL;
+    GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+    if (err != NULL) {
+        fprintf(stderr, "DBUS connection error: %s\n", err->message);
+        g_error_free(err);
+    }
+
+    struct _isu_pkg_list_element *element = pkg_list->head;
+    while (element) {
+        if (!print_status_for_package(conn, element)) {
+            fprintf(stderr, "Can not get status for %s ISU Package\n", element->name);
+        }
+        element = element->next;
+    }
+
+    g_object_unref(conn);
+    return 0;
+}
+
+static int list_isu()
+{
+    isu_pkg_list pkg_list = isu_list_init();
+    if (pkg_list == NULL) {
+        fprintf(stderr, "Can not get the ISU Package list. For more details check the logs.\n");
+        return -1;
+    }
+
+    isu_pkg_info pkg_info;
+    while ((pkg_info = isu_list_next(pkg_list)) != NULL) {
+        char name[127], version[127];
+        isu_pkg_get_name(pkg_info, name, sizeof(name));
+        isu_pkg_get_version(pkg_info, version, sizeof(version));
+        printf("%s (%s)\n", name, version);
+        isu_pkg_info_free(pkg_info);
+    }
+
+    isu_list_free(pkg_list);
+    return 0;
+}
+
+
+static int status_isu(char **argv, int argc)
+{
+    assert(argv);
+
+    struct _isu_pkg_list *pkg_list;
+    if (argc < 3) {
+        pkg_list = get_running_pkgs();
+    } else {
+        pkg_list = get_pkgs_from_argv(argv, argc);
+    }
+    if (pkg_list == NULL) {
+        fprintf(stderr, "Can not get the ISU Package list. For more details check the logs.\n");
+        return -1;
+    }
+    print_status(pkg_list);
+    isu_list_free(pkg_list);
+    return 0;
+}
+
+void print_help(const char *name)
+{
+    printf("Usage:\n");
+    printf("%s <command> <parameters>\n", name);
+
+    printf(" list                      - list installed ISU packages\n");
+    printf(" status [<pkg_name1>, ...] - status of the ISU Package\n");
+    printf(" install <file>            - install ISU package\n");
+    printf(" uninstall <name>          - uninstall ISU pacakge\n");
+    printf("\n");
+}
+
+int main(int argc, char *argv[])
+{
+    if (argc < 2) {
+        print_help(argv[0]);
+        return 0;
+    }
+
+    if (strcmp(argv[1], "install") == 0) {
+        if (argc != 3) {
+            printf("Missing argument\n\n");
+            print_help(argv[0]);
+            return -1;
+        }
+        return install_isu(argv[2]);
+    } else if (strcmp(argv[1], "uninstall") == 0) {
+        if (argc != 3) {
+            printf("Missing argument\n\n");
+            print_help(argv[0]);
+            return -1;
+        }
+        return uninstall_isu(argv[2]);
+    } else if (strcmp(argv[1], "list") == 0) {
+        return list_isu();
+    } else if (strcmp(argv[1], "status") == 0) {
+        return status_isu(argv, argc);
+    } else {
+        print_help(argv[0]);
+        return -1;
+    }
+
+    return 0;
+}