--- /dev/null
+#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;
+}