From c98b0dc7f0894964f1e2e1fd33549f6ef2e8e1f7 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Tue, 24 Oct 2023 12:36:59 +0200 Subject: [PATCH] Add a new ISU package manager Change-Id: I5c10d71bbc9fcf8d0ae89fd6aa43b049e1fda723 --- packaging/isu.spec | 3 +- src/isud/CMakeLists.txt | 2 +- src/pkg_manager/CMakeLists.txt | 10 ++ src/pkg_manager/isu.c | 346 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 src/pkg_manager/CMakeLists.txt create mode 100644 src/pkg_manager/isu.c diff --git a/packaging/isu.spec b/packaging/isu.spec index 361bc6a..475fb29 100644 --- a/packaging/isu.spec +++ b/packaging/isu.spec @@ -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 diff --git a/src/isud/CMakeLists.txt b/src/isud/CMakeLists.txt index 51904a3..bfc10b4 100644 --- a/src/isud/CMakeLists.txt +++ b/src/isud/CMakeLists.txt @@ -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 index 0000000..96d9f48 --- /dev/null +++ b/src/pkg_manager/CMakeLists.txt @@ -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 index 0000000..3471e77 --- /dev/null +++ b/src/pkg_manager/isu.c @@ -0,0 +1,346 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#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 \n", name); + + printf(" list - list installed ISU packages\n"); + printf(" status [, ...] - status of the ISU Package\n"); + printf(" install - install ISU package\n"); + printf(" uninstall - 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; +} -- 2.7.4