diff --git a/Makefile b/Makefile
index faba35a7c344a2af41638678f367f9d59d2c2c6a..6fc816745929c543e5ba725bd83ef38701cd87f2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,9 @@
 PROG = swmodd
-OBJS =swmod.o common.o
+OBJS =swmod.o swmod_host.o swmod_lxc.o swmod_opkg.o swmod_uci.o tools.o
 
-PROG_CFLAGS = $(CFLAGS) -fstrict-aliasing -Wall -Wextra
+PROG_CFLAGS = $(CFLAGS) -fstrict-aliasing
 PROG_LDFLAGS = $(LDFLAGS)
-PROG_LDFLAGS += -luci -lubus -lubox -ljson-c -lblobmsg_json -luuid
+PROG_LDFLAGS += -luci -lubus -lubox -ljson-c -lblobmsg_json -luuid -lopkg -llxc
 
 %.o: %.c
 	$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
diff --git a/common.c b/common.c
deleted file mode 100644
index faccb8baf4c343c2aecdb17acb81c22c99b497c4..0000000000000000000000000000000000000000
--- a/common.c
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * common.c: SWMOD deamon
- *
- * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
- *
- * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#include "common.h"
-
-static struct uci_context *uci_ctx_swmod = NULL;
-
-int swmod_uci_init(void)
-{
-	uci_ctx_swmod = uci_alloc_context();
-	if (!uci_ctx_swmod) {
-		return -1;
-	}
-	uci_add_delta_path(uci_ctx_swmod, uci_ctx_swmod->savedir);
-	uci_set_savedir(uci_ctx_swmod, SWMOD_PATH);
-	uci_set_confdir(uci_ctx_swmod, SWMOD_PATH);
-	return 0;
-}
-
-int swmod_uci_fini(void)
-{
-	if (uci_ctx_swmod) {
-		uci_free_context(uci_ctx_swmod);
-	}
-	return 0;
-}
-
-static bool swmod_uci_validate_section(const char *str)
-{
-	if (!*str)
-		return false;
-
-	for (; *str; str++) {
-		unsigned char c = *str;
-
-		if (isalnum(c) || c == '_')
-			continue;
-
-		return false;
-	}
-	return true;
-}
-
-static int swmod_uci_init_ptr(struct uci_ptr *ptr, char *package, char *section, char *option, char *value)
-{
-	memset(ptr, 0, sizeof(struct uci_ptr));
-
-	/* value */
-	if (value) {
-		ptr->value = value;
-	}
-	ptr->package = package;
-	if (!ptr->package)
-		goto error;
-
-	ptr->section = section;
-	if (!ptr->section) {
-		ptr->target = UCI_TYPE_PACKAGE;
-		goto lastval;
-	}
-
-	ptr->option = option;
-	if (!ptr->option) {
-		ptr->target = UCI_TYPE_SECTION;
-		goto lastval;
-	} else {
-		ptr->target = UCI_TYPE_OPTION;
-	}
-
-lastval:
-	if (ptr->section && !swmod_uci_validate_section(ptr->section))
-		ptr->flags |= UCI_LOOKUP_EXTENDED;
-
-	return 0;
-
-error:
-	return -1;
-}
-
-struct uci_section *swmod_uci_walk_section(char *package, char *section_type, struct uci_section *prev_section)
-{
-	struct uci_ptr ptr;
-	struct uci_element *e;
-	struct uci_section *next_section;
-
-	if (section_type == NULL) {
-		if (prev_section) {
-			e = &prev_section->e;
-			if (e->list.next == &prev_section->package->sections)
-				return NULL;
-			e = container_of(e->list.next, struct uci_element, list);
-			next_section = uci_to_section(e);
-			return next_section;
-		}
-		else {
-			if (swmod_uci_init_ptr(&ptr, package, NULL, NULL, NULL)) {
-				return NULL;
-			}
-			if (uci_lookup_ptr(uci_ctx_swmod, &ptr, NULL, true) != UCI_OK) {
-				return NULL;
-			}
-			if (ptr.p->sections.next == &ptr.p->sections)
-				return NULL;
-			e = container_of(ptr.p->sections.next, struct uci_element, list);
-			next_section = uci_to_section(e);
-
-			return next_section;
-		}
-	}
-	else {
-		struct uci_list *ul = NULL, *shead = NULL;
-
-		if (prev_section) {
-			ul = &prev_section->e.list;
-			shead = &prev_section->package->sections;
-		}
-		else {
-			if (swmod_uci_init_ptr(&ptr, package, NULL, NULL, NULL)) {
-				return NULL;
-			}
-			if (uci_lookup_ptr(uci_ctx_swmod, &ptr, NULL, true) != UCI_OK) {
-				return NULL;
-			}
-			ul = &ptr.p->sections;
-			shead = &ptr.p->sections;
-		}
-		while (ul->next != shead) {
-			e = container_of(ul->next, struct uci_element, list);
-			next_section = uci_to_section(e);
-			if (strcmp(next_section->type, section_type) == 0)
-				return next_section;
-			ul = ul->next;
-		}
-		return NULL;
-	}
-	return NULL;
-}
-
-void swmod_uci_print_list(struct uci_list *uh, char **val, char *delimiter)
-{
-	struct uci_element *e;
-	static char buffer[512];
-	char *buf = buffer;
-	*buf = '\0';
-
-	uci_foreach_element(uh, e) {
-		if (*buf) {
-			strcat(buf, delimiter);
-			strcat(buf, e->name);
-		}
-		else
-			strcpy(buf, e->name);
-	}
-	*val = buf;
-}
-
-struct uci_element *swmod_uci_lookup_list(struct uci_list *list, const char *name)
-{
-	struct uci_element *e;
-
-	uci_foreach_element(list, e) {
-		if (!strcmp(e->name, name))
-			return e;
-	}
-	return NULL;
-}
-
-int swmod_uci_lookup_ptr_by_section(struct uci_ptr *ptr, struct uci_section *section, char *option, char *value)
-{
-	struct uci_element *e;
-	memset(ptr, 0, sizeof(struct uci_ptr));
-
-	ptr->package = section->package->e.name;
-	ptr->section = section->e.name;
-	ptr->option = option;
-	ptr->value = value;
-	ptr->flags |= UCI_LOOKUP_DONE;
-
-	ptr->p = section->package;
-	ptr->s = section;
-
-	if (ptr->option) {
-		e = swmod_uci_lookup_list(&ptr->s->options, ptr->option);
-		if (!e)
-			return UCI_OK;
-		ptr->o = uci_to_option(e);
-		ptr->last = e;
-		ptr->target = UCI_TYPE_OPTION;
-	}
-	else {
-		ptr->last = &ptr->s->e;
-		ptr->target = UCI_TYPE_SECTION;
-	}
-
-	ptr->flags |= UCI_LOOKUP_COMPLETE;
-
-	return UCI_OK;
-}
-
-char *swmod_uci_get_value_by_section(struct uci_section *section, char *option)
-{
-	struct uci_ptr ptr;
-	char *val = "";
-
-	if (swmod_uci_lookup_ptr_by_section(&ptr, section, option, NULL) != UCI_OK)
-		return val;
-
-	if (!ptr.o)
-		return val;
-
-	if(ptr.o->type == UCI_TYPE_LIST) {
-		swmod_uci_print_list(&ptr.o->v.list, &val, " ");
-		return val;
-	}
-
-	if (ptr.o->v.string)
-		return ptr.o->v.string;
-	else
-		return val;
-}
-
-char *swmod_uci_set_value_by_section(struct uci_section *section, char *option, char *value)
-{
-	struct uci_ptr ptr;
-	int ret = UCI_OK;
-
-	if (section == NULL)
-		return "";
-
-	if (swmod_uci_lookup_ptr_by_section(&ptr, section, option, value) != UCI_OK)
-		return "";
-
-	uci_set(uci_ctx_swmod, &ptr);
-
-	if (ret == UCI_OK)
-		ret = uci_save(uci_ctx_swmod, ptr.p);
-
-	if (ptr.o && ptr.o->v.string)
-		return ptr.o->v.string;
-
-	return "";
-}
-
-struct uci_section *swmod_uci_add_section(char *package, char *section_type)
-{
-	struct uci_ptr ptr;
-	struct uci_section *s = NULL;
-
-	if (swmod_uci_init_ptr(&ptr, package, NULL, NULL, NULL))
-		return NULL;
-
-	if (uci_lookup_ptr(uci_ctx_swmod, &ptr, NULL, true) != UCI_OK)
-		return NULL;
-
-	int ret = uci_add_section(uci_ctx_swmod, ptr.p, section_type, &s);
-	if (ret != UCI_OK)
-		return NULL;
-
-	return s;
-}
-
-int swmod_uci_delete_by_section(struct uci_section *section, char *option, char *value)
-{
-	struct uci_ptr ptr = {0};
-
-	if (section == NULL)
-		return -1;
-
-	if (swmod_uci_lookup_ptr_by_section(&ptr, section, option, value) != UCI_OK)
-		return -1;
-
-	if (uci_delete(uci_ctx_swmod, &ptr) != UCI_OK)
-		return -1;
-
-	return 0;
-}
-
-void remove_newline(char *buf)
-{
-	int len;
-	len = strlen(buf) - 1;
-	if (buf[len] == '\n')
-		buf[len] = 0;
-}
-
-char *get_package_name(char *full_name)
-{
-	static char name[32] = "";
-	swmod_strncpy(name, full_name, sizeof(name));
-	char *dot = strchr(name, '.');
-	if (dot)
-		*dot = '\0';
-	return name;
-}
-
-int isfileexist(const char *filepath)
-{
-	if( access( filepath, F_OK ) != -1 )
-	    return 1;
-	else
-		return 0;
-}
-
-int islxcrunning(char *lxc_name)
-{
-	char command[256] = {0}, state[16] = {0};
-	FILE *in;
-
-	if (isfileexist(LXC_INFO)) {
-		snprintf(command, sizeof(command), "lxc-info -n %s | grep State | tr -d ' ' | awk -F':' '{print$2}'", lxc_name);
-		if ((in = popen(command, "r"))) {
-			fgets(state, sizeof(state), in);
-			pclose(in);
-			remove_newline(state);
-		}
-		if (strcmp(state, "RUNNING") == 0)
-			return 1;
-		else
-			return 0;
-	}
-	return 0;
-}
-
-char *convert_url(char *url, char *username, char *password)
-{
-	static char buf[256]= {0};
-
-	if (strncmp(url, "http://", 7) == 0)
-		snprintf(buf, sizeof(buf), "http://%s:%s@%s", username, password, url+7);
-	else if (strncmp(url, "ftp://", 6) == 0)
-		snprintf(buf, sizeof(buf), "ftp://%s:%s@%s", username, password, url+6);
-
-	return buf;
-}
-
-char *generate_uuid(void)
-{
-	uuid_t binuuid;
-	uuid_generate_random(binuuid);
-	char *uuid = malloc(37);
-	uuid_unparse(binuuid, uuid);
-	return uuid;
-}
-
-char *generate_duid(bool sysnchronise, int number)
-{
-	char buf[36] = "0123456789abcdefghijklmnopqrstuvwxyz", euid[16] = {0}, euid_num[8] = {0};
-	int i;
-
-	srand(time(NULL));
-	if (sysnchronise) {
-		for (i = 0; i < 3; i++)
-			euid[i] = buf[rand() % 35];
-		sprintf(euid_num, "%04d", number);
-		strncat(euid, euid_num, 4);
-	} else {
-		for (i = 0; i < 7; i++)
-			euid[i] = buf[rand() % 35];
-	}
-	euid[7] = '\0';
-	return strdup(euid);
-}
-
-int synchronize_deployment_units_with_map_du_file(void)
-{
-	struct uci_section *s = NULL, *stmp = NULL;
-	char path[256] = {0}, line[256] = {0}, name[64] = {0}, version[64] = {0}, command[512] = {0};
-	FILE *log;
-	DIR *dir;
-	struct dirent *ent;
-	int found, incr = 0;
-
-	swmod_uci_foreach_section_safe("map_du", "deployment", stmp, s) {
-		char *map_du_name = swmod_uci_get_value_by_section(s, "name");
-		char *map_du_env = swmod_uci_get_value_by_section(s, "environment");
-		if (strcmp(map_du_env, "OpenWRT_Linux") == 0)
-			snprintf(path, sizeof(path), "%s/%s.control", OPKG_INFO_PATH, map_du_name);
-		else
-			snprintf(path, sizeof(path), "%s/%s/rootfs/%s/%s.control", LXC_PATH, map_du_env, OPKG_INFO_PATH, map_du_name);
-		if (!isfileexist(path))
-			swmod_uci_delete_by_section(s, NULL, NULL);
-	}
-
-	if ((log = popen("opkg list", "r"))) {
-		while(fgets(line, sizeof(line), log) != NULL) {
-			found = 0;
-			if (sscanf(line, "%63s - %63s", name, version)) {
-				swmod_uci_foreach_section("map_du", "deployment", s) {
-					char *map_name = swmod_uci_get_value_by_section(s, "name");
-					char *map_env = swmod_uci_get_value_by_section(s, "environment");
-					if ((strcmp(map_name, name) == 0) && (strcmp(map_env, "OpenWRT_Linux") == 0)) {
-						found = 1;
-						break;
-					}
-				}
-				if (found)
-					continue;
-
-				struct uci_section *new_s = swmod_uci_add_section("map_du", "deployment");
-				char *uuid = generate_uuid();
-				char *duid = generate_duid(true, incr);
-				incr++;
-				swmod_uci_set_value_by_section(new_s, "name", name);
-				swmod_uci_set_value_by_section(new_s, "version", version);
-				swmod_uci_set_value_by_section(new_s, "uuid", uuid);
-				swmod_uci_set_value_by_section(new_s, "duid", duid);
-				swmod_uci_set_value_by_section(new_s, "environment", "OpenWRT_Linux");
-				FREE(uuid);
-				FREE(duid);
-			}
-		}
-		pclose(log);
-	}
-
-	if (isfileexist(LXC_PATH)) {
-		sysfs_foreach_file(LXC_PATH, dir, ent) {
-			if ((strstr(ent->d_name, ".")) || (!islxcrunning(ent->d_name)))
-				continue;
-			snprintf(command, sizeof(command), "lxc-attach -n %s -- opkg list", ent->d_name);
-			if ((log = popen(command, "r"))) {
-				while(fgets(line, sizeof(line), log) != NULL) {
-					found = 0;
-					if (sscanf(line, "%63s - %63s", name, version)) {
-						swmod_uci_foreach_section("map_du", "deployment", s) {
-							char *map_name = swmod_uci_get_value_by_section(s, "name");
-							char *map_env = swmod_uci_get_value_by_section(s, "environment");
-							if ((strcmp(map_name, name) == 0) && (strcmp(map_env, ent->d_name) == 0)) {
-								found = 1;
-								break;
-							}
-						}
-						if (found)
-							continue;
-
-						struct uci_section *new_s = swmod_uci_add_section("map_du", "deployment");
-						char *uuid = generate_uuid();
-						char *duid = generate_duid(true, incr);
-						incr++;
-						swmod_uci_set_value_by_section(new_s, "name", name);
-						swmod_uci_set_value_by_section(new_s, "version", version);
-						swmod_uci_set_value_by_section(new_s, "uuid", uuid);
-						swmod_uci_set_value_by_section(new_s, "duid", duid);
-						swmod_uci_set_value_by_section(new_s, "environment", ent->d_name);
-						FREE(uuid);
-						FREE(duid);
-					}
-				}
-				pclose(log);
-			}
-		}
-		if (dir) closedir(dir);
-	}
-	return 0;
-}
-
-void swmod_add_data_to_list(struct list_head *dup_list, char *cmd, int pid, unsigned int vsize)
-{
-	struct process_res *proc;
-	proc = calloc(1, sizeof(struct process_res));
-	list_add_tail(&proc->list, dup_list);
-	proc->cmd = strdup(cmd);
-	proc->pid = pid;
-	proc->vsize= vsize;
-}
-
-static void swmod_delete_data_from_list(struct process_res *proc)
-{
-	list_del(&proc->list);
-	FREE(proc->cmd);
-	FREE(proc);
-}
-
-void swmod_free_data_from_list(struct list_head *dup_list)
-{
-	struct process_res *proc;
-	while (dup_list->next != dup_list) {
-		proc = list_entry(dup_list->next, struct process_res, list);
-		swmod_delete_data_from_list(proc);
-	}
-}
diff --git a/swmod.c b/swmod.c
index 5b5abf44483f4716ad1ce32a1b856730089e6543..4aa64b70ac44b1d02673e3122b54f92a12e9ecdf 100644
--- a/swmod.c
+++ b/swmod.c
@@ -1,7 +1,7 @@
 /*
- * main.c: SWMOD deamon
+ * swmod.c: SWMOD deamon
  *
- * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
  *
  * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
  *
@@ -22,510 +22,299 @@
  
 #include <stdio.h>
 #include <unistd.h>
+#include <dirent.h>
 #include <libubox/blobmsg.h>
 #include <libubox/uloop.h>
 #include <libubus.h>
 
-#include "common.h"
+#include "swmod_uci.h"
+#include "swmod_opkg.h"
+#include "swmod_lxc.h"
+#include "tools.h"
+#include "swmod_host.h"
+#include "swmod.h"
 
-static int swmod_environment(struct ubus_context *ctx, struct ubus_object *obj,
-									 struct ubus_request_data *req, const char *method,
-									 struct blob_attr *msg)
-{
-	void *a, *t;
-	DIR *dir;
-	struct dirent *ent;
-	FILE *in;
-	char buf[64] = {0}, vendor[64] = {0}, version[64] = {0}, command[512] = {0};
-	char allocated_disk_space[10] = {0}, available_disk_space[10] = {0}, allocated_memory[10] = {0}, available_memory[10] = {0};
-	struct blob_buf bb;
+ExecEnv environments[MAX_ENV] = {0};
+ExecUnit exec_units[MAX_ENV] = {0};
 
-	memset(&bb, 0, sizeof(struct blob_buf));
-	blob_buf_init(&bb, 0);
+enum {
+	INSTALL_PATH,
+	INSTALL_ENV,
+	__INSTALL_MAX
+};
 
-	a = blobmsg_open_array(&bb, "environment");
+enum {
+	REMOVE_NAME,
+	REMOVE_ENV,
+	__REMOVE_MAX
+};
 
-	t = blobmsg_open_table(&bb, "");
-	blobmsg_add_string(&bb, "name", "OpenWRT_Linux");
-	blobmsg_add_string(&bb, "status", "Up");
-	blobmsg_add_string(&bb, "type", "Linux");
+enum {
+	DU_INSTALL_URL,
+	DU_INSTALL_UUID,
+	DU_INSTALL_USERNAME,
+	DU_INSTALL_PASSWORD,
+	DU_INSTALL_ENV,
+	__DU_INSTALL_MAX
+};
 
-	if ((in = popen("uname -o", "r"))) {
-		fgets(buf, sizeof(buf), in);
-		pclose(in);
-		remove_newline(buf);
-		swmod_strncpy(vendor, buf, sizeof(vendor));
-	}
-	blobmsg_add_string(&bb, "vendor", vendor);
+enum {
+	DU_UPDATE_UUID,
+	DU_UPDATE_URL,
+	DU_UPDATE_VERSION,
+	DU_UPDATE_USERNAME,
+	DU_UPDATE_PASSWORD,
+	__DU_UPDATE_MAX
+};
 
-	if ((in = popen("uname -r", "r"))) {
-		fgets(buf, sizeof(buf), in);
-		pclose(in);
-		remove_newline(buf);
-		swmod_strncpy(version, buf, sizeof(version));
-	}
-	blobmsg_add_string(&bb, "version", version);
+enum {
+	DU_UNINSTALL_NAME,
+	DU_UNINSTALL_ENV,
+	__DU_UNINSTALL_MAX
+};
 
-	if ((in = popen("free | grep Mem | awk '{print$2}'", "r"))) {
-		fgets(buf, sizeof(buf), in);
-		pclose(in);
-		remove_newline(buf);
-		swmod_strncpy(allocated_disk_space, buf, sizeof(allocated_disk_space));
-	}
-	blobmsg_add_u32(&bb, "allocated_disk_space", atoi(allocated_disk_space));
+static const struct blobmsg_policy install_policy[__INSTALL_MAX] = {
+	[INSTALL_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+	[INSTALL_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
+};
 
-	if ((in = popen("free | grep Mem | awk '{print$4}'", "r"))) {
-		fgets(buf, sizeof(buf), in);
-		pclose(in);
-		remove_newline(buf);
-		swmod_strncpy(available_disk_space, buf, sizeof(available_disk_space));
-	}
-	blobmsg_add_u32(&bb, "available_disk_space", atoi(available_disk_space));
+static const struct blobmsg_policy remove_policy[__REMOVE_MAX] = {
+	[REMOVE_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
+	[REMOVE_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
+};
 
-	if ((in = popen("df | grep overlayfs | awk '{print$2}'", "r"))) {
-		fgets(buf, sizeof(buf), in);
-		pclose(in);
-		remove_newline(buf);
-		swmod_strncpy(allocated_memory, buf, sizeof(allocated_memory));
-	}
-	blobmsg_add_u32(&bb, "allocated_memory", atoi(allocated_memory));
+static const struct blobmsg_policy du_install_policy[__DU_INSTALL_MAX] = {
+	[DU_INSTALL_URL] = { .name = "url", .type = BLOBMSG_TYPE_STRING },
+	[DU_INSTALL_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING },
+	[DU_INSTALL_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING },
+	[DU_INSTALL_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING },
+	[DU_INSTALL_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
+};
 
-	if ((in = popen("df | grep overlayfs | awk '{print$4}'", "r"))) {
-		fgets(buf, sizeof(buf), in);
-		pclose(in);
-		remove_newline(buf);
-		swmod_strncpy(available_memory, buf, sizeof(available_memory));
-	}
-	blobmsg_add_u32(&bb, "available_memory", atoi(available_memory));
-	blobmsg_close_table(&bb, t);
+static const struct blobmsg_policy du_update_policy[__DU_UPDATE_MAX] = {
+	[DU_UPDATE_UUID] = { .name = "uuid", .type = BLOBMSG_TYPE_STRING },
+	[DU_UPDATE_URL] = { .name = "url", .type = BLOBMSG_TYPE_STRING },
+	[DU_UPDATE_VERSION] = { .name = "version", .type = BLOBMSG_TYPE_STRING },
+	[DU_UPDATE_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING },
+	[DU_UPDATE_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING },
+};
 
-	if (isfileexist(LXC_PATH)) {
-		sysfs_foreach_file(LXC_PATH, dir, ent) {
-			if (strstr(ent->d_name, "."))
-				continue;
-			t = blobmsg_open_table(&bb, "");
-			blobmsg_add_string(&bb, "name", ent->d_name);
-
-			if (islxcrunning(ent->d_name))
-				blobmsg_add_string(&bb, "status", "Up");
-			else
-				blobmsg_add_string(&bb, "status", "Disabled");
-
-			blobmsg_add_string(&bb, "type", "Linux Container");
-
-			if (islxcrunning(ent->d_name))
-				blobmsg_add_string(&bb, "vendor", "");
-			else {
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- uname -o", ent->d_name);
-				if ((in = popen(command, "r"))) {
-					fgets(buf, sizeof(buf), in);
-					pclose(in);
-					remove_newline(buf);
-					swmod_strncpy(vendor, buf, sizeof(vendor));
-				}
-				blobmsg_add_string(&bb, "vendor", vendor);
-			}
+static const struct blobmsg_policy du_uninstall_policy[__DU_UNINSTALL_MAX] = {
+	[DU_UNINSTALL_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
+	[DU_UNINSTALL_ENV] = { .name = "environment", .type = BLOBMSG_TYPE_STRING },
+};
 
-			if (islxcrunning(ent->d_name))
-				blobmsg_add_string(&bb, "version", "");
-			else {
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- uname -r", ent->d_name);
-				if ((in = popen(command, "r"))) {
-					fgets(buf, sizeof(buf), in);
-					pclose(in);
-					remove_newline(buf);
-					swmod_strncpy(version, buf, sizeof(version));
-				}
-				blobmsg_add_string(&bb, "version", version);
-			}
+static void
+populate_environments(void)
+{
+	memset(environments, '\0', sizeof(environments));
 
-			if (islxcrunning(ent->d_name))
-				blobmsg_add_u32(&bb, "allocated_disk_space", 0);
-			else {
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- free | grep Mem | awk '{print$2}'", ent->d_name);
-				if ((in = popen(command, "r"))) {
-					fgets(buf, sizeof(buf), in);
-					pclose(in);
-					remove_newline(buf);
-					swmod_strncpy(allocated_disk_space, buf, sizeof(allocated_disk_space));
-				}
-				blobmsg_add_u32(&bb, "allocated_disk_space", atoi(allocated_disk_space));
-			}
+	/* Host system */
+	populate_host_system_environment();
 
-			if (islxcrunning(ent->d_name))
-				blobmsg_add_u32(&bb, "available_disk_space", 0);
-			else {
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- free | grep Mem | awk '{print$4}'", ent->d_name);
-				if ((in = popen(command, "r"))) {
-					fgets(buf, sizeof(buf), in);
-					pclose(in);
-					remove_newline(buf);
-					swmod_strncpy(available_disk_space, buf, sizeof(available_disk_space));
-				}
-				blobmsg_add_u32(&bb, "available_disk_space", atoi(available_disk_space));
-			}
+	/* Linux containers */
+	populate_lxc_environment();
+}
 
-			if (islxcrunning(ent->d_name))
-				blobmsg_add_u32(&bb, "allocated_memory", 0);
-			else {
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- df | grep overlayfs | awk '{print$2}'", ent->d_name);
-				if ((in = popen(command, "r"))) {
-					fgets(buf, sizeof(buf), in);
-					pclose(in);
-					remove_newline(buf);
-					swmod_strncpy(allocated_memory, buf, sizeof(allocated_memory));
-				}
-				blobmsg_add_u32(&bb, "allocated_memory", atoi(allocated_memory));
-			}
+static int
+swmod_environment(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
+{
+	struct blob_buf bb;
+	void *a, *t;
+	int i;
 
-			if (islxcrunning(ent->d_name))
-				blobmsg_add_u32(&bb, "available_memory", 0);
-			else {
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- df | grep overlayfs | awk '{print$4}'", ent->d_name);
-				if ((in = popen(command, "r"))) {
-					fgets(buf, sizeof(buf), in);
-					pclose(in);
-					remove_newline(buf);
-					swmod_strncpy(available_memory, buf, sizeof(available_memory));
-				}
-				blobmsg_add_u32(&bb, "available_memory", atoi(available_memory));
-			}
+	populate_environments();
 
-			blobmsg_close_table(&bb, t);
-		}
-		if (dir) closedir(dir);
+	memset(&bb, 0, sizeof(struct blob_buf));
+	blob_buf_init(&bb, 0);
+
+	a = blobmsg_open_array(&bb, "environment");
+
+	for (i = 0; i < MAX_ENV; i++) {
+		if (!environments[i].exists)
+			continue;
+
+		t = blobmsg_open_table(&bb, "");
+
+		blobmsg_add_string(&bb, "name", environments[i].name);
+		blobmsg_add_string(&bb, "status", environments[i].status);
+		blobmsg_add_string(&bb, "type", environments[i].type);
+		blobmsg_add_string(&bb, "vendor", environments[i].vendor);
+		blobmsg_add_string(&bb, "version", environments[i].version);
+		blobmsg_add_u64(&bb, "allocated_disk_space", environments[i].allocated_disk_space);
+		blobmsg_add_u64(&bb, "available_disk_space", environments[i].available_disk_space);
+		blobmsg_add_u64(&bb, "allocated_memory", environments[i].allocated_memory);
+		blobmsg_add_u64(&bb, "available_memory", environments[i].available_memory);
+
+		blobmsg_close_table(&bb, t);
 	}
 
 	blobmsg_close_array(&bb, a);
+
 	ubus_send_reply(ctx, req, bb.head);
 	blob_buf_free(&bb);
 	return 0;
 }
 
-enum {
-	INSTALL_PATH,
-	INSTALL_ENV,
-	__INSTALL_MAX
-};
-
-static const struct blobmsg_policy install_policy[__INSTALL_MAX] = {
-	[INSTALL_PATH]     = { .name = "path",     .type = BLOBMSG_TYPE_STRING },
-	[INSTALL_ENV]     = { .name = "environment",     .type = BLOBMSG_TYPE_STRING },
-};
-
-static int swmod_install(struct ubus_context *ctx, struct ubus_object *obj,
-						struct ubus_request_data *req, const char *method,
-						struct blob_attr *msg)
+static int
+swmod_install(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
 {
 	struct blob_attr *tb[__INSTALL_MAX] = {NULL};
-	char line[512] = {0}, command[512] = {0}, package_path[256] = {0};
 	struct blob_buf bb;
-	struct dirent *ent;
-	DIR *dir;
-	FILE *log;
-	int found;
 
-	if(blobmsg_parse(install_policy, __INSTALL_MAX, tb, blob_data(msg), blob_len(msg)))
+	if (blobmsg_parse(install_policy, __INSTALL_MAX, tb, blob_data(msg), blob_len(msg)))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
-	if (tb[INSTALL_PATH]) {
-		swmod_strncpy(package_path, blobmsg_get_string(tb[INSTALL_PATH]), sizeof(package_path));
-		if (!isfileexist(package_path))
-			return UBUS_STATUS_INVALID_ARGUMENT;
-	} else {
+	if (!tb[INSTALL_PATH])
 		return UBUS_STATUS_INVALID_ARGUMENT;
-	}
 
-	if (tb[INSTALL_ENV]) {
-		found = 0;
-		if (strcmp(blobmsg_get_string(tb[INSTALL_ENV]), "OpenWRT_Linux") != 0) {
-			if (isfileexist(LXC_PATH)) {
-				sysfs_foreach_file(LXC_PATH, dir, ent) {
-					if (strcmp(blobmsg_get_string(tb[INSTALL_ENV]), ent->d_name) == 0) {
-						found = 1;
-						break;
-					}
-				}
-				if (dir) closedir(dir);
-				if (!found)
-					return UBUS_STATUS_INVALID_ARGUMENT;
-			} else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		}
-		if (found) {
-			if (islxcrunning(blobmsg_get_string(tb[INSTALL_ENV])))
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- opkg install %s 2>/dev/null", blobmsg_get_string(tb[INSTALL_ENV]), package_path);
-			else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		} else
-			snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", package_path);
-	} else {
-		snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", package_path);
-	}
-
-	memset(&bb,0,sizeof(struct blob_buf));
+	memset(&bb, 0, sizeof(struct blob_buf));
 	blob_buf_init(&bb, 0);
 
-	if ((log = popen(command, "r"))) {
-		while (fgets(line, sizeof(line), log) != NULL) {
-			if (strstr(line, "Configuring")) {
-				blobmsg_add_u8(&bb,"status", true);
-				break;
-			} else if (strstr(line, "Unknown package")) {
-				blobmsg_add_u8(&bb,"status", false);
-				blobmsg_add_string(&bb, "error", "Cannot install package");
-				break;
-			} else if (strstr(line, "up to date")) {
-				blobmsg_add_u8(&bb,"status", false);
-				blobmsg_add_string(&bb, "error", "This package is already installed with the same version");
-				break;
-			} else if (strstr(line, "Not downgrading package")) {
-				blobmsg_add_u8(&bb,"status", false);
-				blobmsg_add_string(&bb, "error", "Cannot downgrade package");
-				break;
-			} else {
-				blobmsg_add_u8(&bb,"status", false);
-				blobmsg_add_string(&bb, "error", "dependencies package");
-				break;
-			}
-		}
-		pclose(log);
-	}
+	int err = swmod_install_remove_package(blobmsg_get_string(tb[INSTALL_PATH]),
+			blobmsg_get_string(tb[INSTALL_ENV]),
+			SWMOD_INSTALL);
+
+	blobmsg_add_u8(&bb, "status", (!err) ? true : false);
 
 	ubus_send_reply(ctx, req, bb.head);
 	blob_buf_free(&bb);
 	return 0;
 }
 
-enum {
-	REMOVE_NAME,
-	REMOVE_ENV,
-	__REMOVE_MAX
-};
-
-static const struct blobmsg_policy remove_policy[__REMOVE_MAX] = {
-	[REMOVE_NAME]     = { .name = "name",     .type = BLOBMSG_TYPE_STRING },
-	[REMOVE_ENV]     = { .name = "environment",     .type = BLOBMSG_TYPE_STRING },
-};
-
-static int swmod_remove(struct ubus_context *ctx, struct ubus_object *obj,
-					   struct ubus_request_data *req, const char *method,
-					   struct blob_attr *msg)
+static int
+swmod_remove(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
 {
 	struct blob_attr *tb[__REMOVE_MAX] = {NULL};
 	struct blob_buf bb;
-	char line[512] = {0}, command[256] = {0};
-	struct dirent *ent;
-	DIR *dir;
-	FILE *log;
-	int found;
 
-	if(blobmsg_parse(remove_policy, __REMOVE_MAX, tb, blob_data(msg), blob_len(msg)))
+	if (blobmsg_parse(remove_policy, __REMOVE_MAX, tb, blob_data(msg), blob_len(msg)))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
 	if (!tb[REMOVE_NAME])
 		return UBUS_STATUS_INVALID_ARGUMENT;
 
-	if (tb[REMOVE_ENV]) {
-		found = 0;
-		if (strcmp(blobmsg_get_string(tb[REMOVE_ENV]), "OpenWRT_Linux") != 0) {
-			if (isfileexist(LXC_PATH)) {
-				sysfs_foreach_file(LXC_PATH, dir, ent) {
-					if (strcmp(blobmsg_get_string(tb[REMOVE_ENV]), ent->d_name) == 0) {
-						found = 1;
-						break;
-					}
-				}
-				if (dir) closedir(dir);
-				if (!found)
-					return UBUS_STATUS_INVALID_ARGUMENT;
-			} else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		}
-		if (found) {
-			if (islxcrunning(blobmsg_get_string(tb[REMOVE_ENV])))
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- opkg install %s 2>/dev/null", blobmsg_get_string(tb[REMOVE_ENV]), blobmsg_get_string(tb[REMOVE_NAME]));
-			else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		} else
-			snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", blobmsg_get_string(tb[REMOVE_NAME]));
-	} else {
-		snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", blobmsg_get_string(tb[REMOVE_NAME]));
-	}
-
-	memset(&bb,0,sizeof(struct blob_buf));
+	memset(&bb, 0, sizeof(struct blob_buf));
 	blob_buf_init(&bb, 0);
 
-	if ((log = popen(command, "r"))) {
-		while(fgets(line, sizeof(line), log) != NULL) {
-			if (strstr(line, "Removing package")) {
-				blobmsg_add_u8(&bb,"status", true);
-				break;
-			} else if (strstr(line, "No packages removed")) {
-				blobmsg_add_u8(&bb,"status", false);
-				blobmsg_add_string(&bb, "error", "Cannot remove package");
-				break;
-			}
-		}
-		pclose(log);
-	}
+	int err = swmod_install_remove_package(blobmsg_get_string(tb[REMOVE_NAME]),
+			blobmsg_get_string(tb[REMOVE_ENV]),
+			SWMOD_REMOVE);
+
+	blobmsg_add_u8(&bb, "status", (!err) ? true : false);
 
 	ubus_send_reply(ctx, req, bb.head);
 	blob_buf_free(&bb);
 	return 0;
 }
 
-enum {
-	DU_INSTALL_URL,
-	DU_INSTALL_UUID,
-	DU_INSTALL_USERNAME,
-	DU_INSTALL_PASSWORD,
-	DU_INSTALL_ENV,
-	__DU_INSTALL_MAX
-};
+static int
+update_map_du_file(struct blob_buf *bb, char *pkg_name,
+		char *pkg_version, char *url, char *username,
+		char *password, char *env, char *uuid)
+{
+	char lxc_map_du_path[128] = {0};
+
+	if (!env || strcmp(env, HOST_SYSTEM) == 0)
+		swmod_strncpy(lxc_map_du_path, HOST_SYSTEM, 14);
+	else {
+		const char *lxc_config_path = get_lxc_path_from_config();
+		snprintf(lxc_map_du_path, sizeof(lxc_map_du_path), "%s/%s/rootfs%s",
+				lxc_config_path ? lxc_config_path : "",
+				env,
+				SWMOD_PATH);
+	}
 
-static const struct blobmsg_policy du_install_policy[__DU_INSTALL_MAX] = {
-	[DU_INSTALL_URL]     = { .name = "url",     .type = BLOBMSG_TYPE_STRING },
-	[DU_INSTALL_UUID]     = { .name = "uuid",     .type = BLOBMSG_TYPE_STRING },
-	[DU_INSTALL_USERNAME]     = { .name = "username",     .type = BLOBMSG_TYPE_STRING },
-	[DU_INSTALL_PASSWORD]     = { .name = "password",     .type = BLOBMSG_TYPE_STRING },
-	[DU_INSTALL_ENV]     = { .name = "environment",     .type = BLOBMSG_TYPE_STRING },
-};
+	swmod_uci_init(lxc_map_du_path);
+
+	struct uci_section *new_s = swmod_uci_add_section(SWMOD_MAP_DU, "deployment");
 
-static int swmod_du_install(struct ubus_context *ctx, struct ubus_object *obj,
-						   struct ubus_request_data *req, const char *method,
-						   struct blob_attr *msg)
+	swmod_uci_set_value_by_section(new_s, "name", pkg_name);
+	swmod_uci_set_value_by_section(new_s, "version", pkg_version);
+	swmod_uci_set_value_by_section(new_s, "url", url);
+
+	if (username && *username != '\0')
+		swmod_uci_set_value_by_section(new_s, "username", username);
+
+	if (password && *password != '\0')
+		swmod_uci_set_value_by_section(new_s, "password", password);
+
+	if (env) {
+		swmod_uci_set_value_by_section(new_s, "environment", env);
+		blobmsg_add_string(bb,"environment", env);
+	} else {
+		swmod_uci_set_value_by_section(new_s, "environment", HOST_SYSTEM);
+		blobmsg_add_string(bb,"environment", HOST_SYSTEM);
+	}
+
+	if (uuid && *uuid != '\0') {
+		//use the given UUID
+		swmod_uci_set_value_by_section(new_s, "uuid", uuid);
+		blobmsg_add_string(bb,"uuid", uuid);
+	} else {
+		//generate a UUID
+		char *new_uuid = generate_uuid();
+		swmod_uci_set_value_by_section(new_s, "uuid", new_uuid);
+		blobmsg_add_string(bb,"uuid", new_uuid);
+		FREE(new_uuid);
+	}
+
+	//generate a DUID
+	char *duid = generate_duid(false, 0);
+	swmod_uci_set_value_by_section(new_s, "duid", duid);
+	FREE(duid);
+
+	swmod_uci_fini(SWMOD_MAP_DU);
+
+	return 0;
+}
+
+static int
+swmod_du_install(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
 {
 	struct blob_attr *tb[__DU_INSTALL_MAX] = {NULL};
-	char line[512] = {0}, command[512] = {0}, name[64] = {0}, version[64] = {0};
-	DIR *dir;
-	struct dirent *ent;
 	struct blob_buf bb;
-	int i = 0, found;
-	FILE *log;
 
-	if(blobmsg_parse(du_install_policy, __DU_INSTALL_MAX, tb, blob_data(msg), blob_len(msg)))
+	if (blobmsg_parse(du_install_policy, __DU_INSTALL_MAX, tb, blob_data(msg), blob_len(msg)))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
 	if (!tb[DU_INSTALL_URL])
 		return UBUS_STATUS_INVALID_ARGUMENT;
 
-	if (tb[DU_INSTALL_ENV]) {
-		found = 0;
-		if (strcmp(blobmsg_get_string(tb[DU_INSTALL_ENV]), "OpenWRT_Linux") != 0) {
-			if (isfileexist(LXC_PATH)) {
-				sysfs_foreach_file(LXC_PATH, dir, ent) {
-					if (strcmp(blobmsg_get_string(tb[DU_INSTALL_ENV]), ent->d_name) == 0) {
-						found = 1;
-						break;
-					}
-				}
-				if (dir) closedir(dir);
-				if (!found)
-					return UBUS_STATUS_INVALID_ARGUMENT;
-			} else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		}
-		if (found) {
-			if (islxcrunning(blobmsg_get_string(tb[DU_INSTALL_ENV]))) {
-				if (tb[DU_INSTALL_USERNAME] &&
-					*(blobmsg_get_string(tb[DU_INSTALL_USERNAME])) != '\0' &&
-					tb[DU_INSTALL_PASSWORD] &&
-					*(blobmsg_get_string(tb[DU_INSTALL_PASSWORD])) != '\0') {
-					char *url = convert_url(blobmsg_get_string(tb[DU_INSTALL_URL]), blobmsg_get_string(tb[DU_INSTALL_USERNAME]), blobmsg_get_string(tb[DU_INSTALL_PASSWORD]));
-					snprintf(command, sizeof(command), "lxc-attach -n %s -- opkg install %s 2>/dev/null", blobmsg_get_string(tb[DU_INSTALL_ENV]), url);
-				} else
-					snprintf(command, sizeof(command), "lxc-attach -n %s -- opkg install %s 2>/dev/null", blobmsg_get_string(tb[DU_INSTALL_ENV]), blobmsg_get_string(tb[DU_INSTALL_URL]));
-			} else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		} else {
-			if (tb[DU_INSTALL_USERNAME] &&
-				*(blobmsg_get_string(tb[DU_INSTALL_USERNAME])) != '\0' &&
-				tb[DU_INSTALL_PASSWORD] &&
-				*(blobmsg_get_string(tb[DU_INSTALL_PASSWORD])) != '\0') {
-				char *url = convert_url(blobmsg_get_string(tb[DU_INSTALL_URL]), blobmsg_get_string(tb[DU_INSTALL_USERNAME]), blobmsg_get_string(tb[DU_INSTALL_PASSWORD]));
-				snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", url);
-			} else
-				snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", blobmsg_get_string(tb[DU_INSTALL_URL]));
-		}
-	} else {
-		if (tb[DU_INSTALL_USERNAME] &&
-			*(blobmsg_get_string(tb[DU_INSTALL_USERNAME])) != '\0' &&
-			tb[DU_INSTALL_PASSWORD] &&
-			*(blobmsg_get_string(tb[DU_INSTALL_PASSWORD])) != '\0') {
-			char *url = convert_url(blobmsg_get_string(tb[DU_INSTALL_URL]), blobmsg_get_string(tb[DU_INSTALL_USERNAME]), blobmsg_get_string(tb[DU_INSTALL_PASSWORD]));
-			snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", url);
-		} else
-			snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", blobmsg_get_string(tb[DU_INSTALL_URL]));
-	}
-
 	synchronize_deployment_units_with_map_du_file();
 
-	memset(&bb,0,sizeof(struct blob_buf));
+	memset(&bb, 0, sizeof(struct blob_buf));
 	blob_buf_init(&bb, 0);
 
-	if ((log = popen(command, "r"))) {
-		while(fgets(line, sizeof(line), log) != NULL) {
-			if (strstr(line, "Downloading"))
-				i++;
+	char *full_url = generate_full_url(blobmsg_get_string(tb[DU_INSTALL_URL]),
+			blobmsg_get_string(tb[DU_INSTALL_USERNAME]),
+			blobmsg_get_string(tb[DU_INSTALL_PASSWORD]));
 
-			if (strstr(line, "Installing") || strstr(line, "installed")) {
-				sscanf(line, "Installing %63s (%63[^)] to root...", name, version);
-				i++;
-			}
+	int err = swmod_install_remove_package(full_url,
+			blobmsg_get_string(tb[DU_INSTALL_ENV]),
+			SWMOD_INSTALL);
 
-			if (strstr(line, "Configuring"))
-				i++;
-		}
-		pclose(log);
-	}
+	blobmsg_add_u8(&bb, "status", (!err) ? true : false);
 
-	if (i == 1) {
-		blobmsg_add_u8(&bb,"status", false);
-		blobmsg_add_string(&bb,"error", "Download");
-	} else if (i == 2) {
-		blobmsg_add_u8(&bb,"status", false);
-		blobmsg_add_string(&bb,"error", "Install");
-	} else {
-		blobmsg_add_u8(&bb,"status", true);
-		blobmsg_add_string(&bb,"name", name);
-		blobmsg_add_string(&bb,"version", version);
-
-		struct uci_section *new_s = swmod_uci_add_section("map_du", "deployment");
-		swmod_uci_set_value_by_section(new_s, "name", name);
-		swmod_uci_set_value_by_section(new_s, "version", version);
-		swmod_uci_set_value_by_section(new_s, "url", blobmsg_get_string(tb[DU_INSTALL_URL]));
-
-		if (tb[DU_INSTALL_USERNAME] && *(blobmsg_get_string(tb[DU_INSTALL_USERNAME])) != '\0')
-			swmod_uci_set_value_by_section(new_s, "username", blobmsg_get_string(tb[DU_INSTALL_USERNAME]));
-
-		if (tb[DU_INSTALL_PASSWORD] && *(blobmsg_get_string(tb[DU_INSTALL_PASSWORD])) != '\0')
-			swmod_uci_set_value_by_section(new_s, "password", blobmsg_get_string(tb[DU_INSTALL_PASSWORD]));
-
-		if (tb[DU_INSTALL_ENV]) {
-			swmod_uci_set_value_by_section(new_s, "environment", blobmsg_get_string(tb[DU_INSTALL_ENV]));
-			blobmsg_add_string(&bb,"environment", blobmsg_get_string(tb[DU_INSTALL_ENV]));
-		} else {
-			swmod_uci_set_value_by_section(new_s, "environment", "OpenWRT_Linux");
-			blobmsg_add_string(&bb,"environment", "OpenWRT_Linux");
-		}
+	if (!err) {
+		blobmsg_add_string(&bb,"name", package_name);
+		blobmsg_add_string(&bb,"version", package_version);
 
-		if (tb[DU_INSTALL_UUID] && *(blobmsg_get_string(tb[DU_INSTALL_UUID])) != '\0') {
-			//use the given UUID
-			swmod_uci_set_value_by_section(new_s, "uuid", blobmsg_get_string(tb[DU_INSTALL_UUID]));
-			blobmsg_add_string(&bb,"uuid", blobmsg_get_string(tb[DU_INSTALL_UUID]));
-		} else {
-			//generate a UUID
-			char *uuid = generate_uuid();
-			swmod_uci_set_value_by_section(new_s, "uuid", uuid);
-			blobmsg_add_string(&bb,"uuid", uuid);
-			FREE(uuid);
-		}
-
-		//generate a DUID
-		char *duid = generate_duid(false, 0);
-		swmod_uci_set_value_by_section(new_s, "duid", duid);
-		FREE(duid);
+		// Update map file with this installed package
+		update_map_du_file(&bb, package_name, package_version,
+				blobmsg_get_string(tb[DU_INSTALL_URL]),
+				blobmsg_get_string(tb[DU_INSTALL_USERNAME]),
+				blobmsg_get_string(tb[DU_INSTALL_PASSWORD]),
+				blobmsg_get_string(tb[DU_INSTALL_ENV]),
+				blobmsg_get_string(tb[DU_INSTALL_UUID]));
 	}
 
 	ubus_send_reply(ctx, req, bb.head);
@@ -533,308 +322,206 @@ static int swmod_du_install(struct ubus_context *ctx, struct ubus_object *obj,
 	return 0;
 }
 
-enum {
-	DU_UPDATE_UUID,
-	DU_UPDATE_URL,
-	DU_UPDATE_VERSION,
-	DU_UPDATE_USERNAME,
-	DU_UPDATE_PASSWORD,
-	__DU_UPDATE_MAX
-};
+static int
+update_corresponding_section_in_map_du_file(char *pkg_version, char *url,
+		char *username, char *password, char *env, char *uuid)
+{
+	char lxc_map_du_path[128] = {0};
+
+	if (!env || strcmp(env, HOST_SYSTEM) == 0)
+		swmod_strncpy(lxc_map_du_path, SWMOD_PATH, 12);
+	else {
+		const char *lxc_config_path = get_lxc_path_from_config();
+		snprintf(lxc_map_du_path, sizeof(lxc_map_du_path), "%s/%s/rootfs%s",
+				lxc_config_path ? lxc_config_path : "",
+				env,
+				SWMOD_PATH);
+	}
 
-static const struct blobmsg_policy du_update_policy[__DU_UPDATE_MAX] = {
-	[DU_UPDATE_UUID]     = { .name = "uuid",     .type = BLOBMSG_TYPE_STRING },
-	[DU_UPDATE_URL]     = { .name = "url",     .type = BLOBMSG_TYPE_STRING },
-	[DU_UPDATE_VERSION]     = { .name = "version",     .type = BLOBMSG_TYPE_STRING },
-	[DU_UPDATE_USERNAME]     = { .name = "username",     .type = BLOBMSG_TYPE_STRING },
-	[DU_UPDATE_PASSWORD]     = { .name = "password",     .type = BLOBMSG_TYPE_STRING },
-};
+	swmod_uci_init(lxc_map_du_path);
+
+	struct uci_section *s = NULL;
+	swmod_uci_foreach_section(SWMOD_MAP_DU, "deployment", s) {
+		char *map_uuid = swmod_uci_get_value_by_section(s, "uuid");
+		if (strcmp(map_uuid, uuid) == 0) {
+			swmod_uci_set_value_by_section(s, "version", pkg_version);
+			swmod_uci_set_value_by_section(s, "url", url);
+
+			if (username && *username != '\0')
+				swmod_uci_set_value_by_section(s, "username", username);
+
+			if (password && *password != '\0')
+				swmod_uci_set_value_by_section(s, "password", password);
+			break;
+		}
+	}
 
+	swmod_uci_fini(SWMOD_MAP_DU);
 
-static int swmod_du_update(struct ubus_context *ctx, struct ubus_object *obj,
-						  struct ubus_request_data *req, const char *method,
-						  struct blob_attr *msg)
+	return 0;
+}
+
+static int
+swmod_du_update(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
 {
 	struct blob_attr *tb[__DU_UPDATE_MAX] = {NULL};
-	char line[512] = {0}, command[512] = {0}, name[64] = {0}, version[64] = {0};
-	char *map_env = NULL, *map_uuid = NULL;
 	struct blob_buf bb;
-	struct uci_section *s = NULL;
-	DIR *dir;
-	struct dirent *ent;
-	int i = 0, found;
-	FILE *log;
 
-	if(blobmsg_parse(du_update_policy, __DU_UPDATE_MAX, tb, blob_data(msg), blob_len(msg)))
+	if (blobmsg_parse(du_update_policy, __DU_UPDATE_MAX, tb, blob_data(msg), blob_len(msg)))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
-	if (!tb[DU_UPDATE_URL])
+	if (!tb[DU_UPDATE_URL] || !tb[DU_UPDATE_UUID])
 		return UBUS_STATUS_INVALID_ARGUMENT;
 
 	synchronize_deployment_units_with_map_du_file();
 
-	swmod_uci_foreach_section("map_du", "deployment", s) {
-		map_uuid = swmod_uci_get_value_by_section(s, "uuid");
-		if (strcmp(map_uuid, blobmsg_get_string(tb[DU_UPDATE_UUID])) == 0) {
-			map_env = swmod_uci_get_value_by_section(s, "environment");
-			swmod_uci_set_value_by_section(s, "url", blobmsg_get_string(tb[DU_UPDATE_URL]));
-			if (tb[DU_UPDATE_USERNAME] && *(blobmsg_get_string(tb[DU_UPDATE_USERNAME])) != '\0')
-				swmod_uci_set_value_by_section(s, "username", blobmsg_get_string(tb[DU_UPDATE_USERNAME]));
-			if (tb[DU_UPDATE_PASSWORD] && *(blobmsg_get_string(tb[DU_UPDATE_PASSWORD])) != '\0')
-				swmod_uci_set_value_by_section(s, "password", blobmsg_get_string(tb[DU_UPDATE_PASSWORD]));
-			break;
-		}
-	}
-	if (map_env) {
-		found = 0;
-		if (strcmp(map_env, "OpenWRT_Linux") != 0) {
-			if (isfileexist(LXC_PATH)) {
-				sysfs_foreach_file(LXC_PATH, dir, ent) {
-					if (strcmp(map_env, ent->d_name) == 0) {
-						found = 1;
-						break;
-					}
-				}
-				if (dir) closedir(dir);
-				if (!found)
-					return UBUS_STATUS_INVALID_ARGUMENT;
-			} else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		}
-		if (found) {
-			if (islxcrunning(map_env)) {
-				if (tb[DU_UPDATE_USERNAME] &&
-					*(blobmsg_get_string(tb[DU_UPDATE_USERNAME])) != '\0' &&
-					tb[DU_UPDATE_PASSWORD] &&
-					*(blobmsg_get_string(tb[DU_UPDATE_PASSWORD])) != '\0') {
-					char *url = convert_url(blobmsg_get_string(tb[DU_UPDATE_URL]), blobmsg_get_string(tb[DU_UPDATE_USERNAME]), blobmsg_get_string(tb[DU_UPDATE_PASSWORD]));
-					snprintf(command, sizeof(command), "lxc-attach -n %s -- opkg install %s 2>/dev/null", map_env, url);
-				} else
-					snprintf(command, sizeof(command), "lxc-attach -n %s -- opkg install %s 2>/dev/null", map_env, blobmsg_get_string(tb[DU_UPDATE_URL]));
-			} else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		} else {
-			if (tb[DU_UPDATE_USERNAME] &&
-				*(blobmsg_get_string(tb[DU_UPDATE_USERNAME])) != '\0' &&
-				tb[DU_UPDATE_PASSWORD] &&
-				*(blobmsg_get_string(tb[DU_UPDATE_PASSWORD])) != '\0') {
-				char *url = convert_url(blobmsg_get_string(tb[DU_UPDATE_URL]), blobmsg_get_string(tb[DU_UPDATE_USERNAME]), blobmsg_get_string(tb[DU_UPDATE_PASSWORD]));
-				snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", url);
-			} else
-				snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", blobmsg_get_string(tb[DU_UPDATE_URL]));
-		}
-	} else {
-		if (tb[DU_UPDATE_USERNAME] &&
-			*(blobmsg_get_string(tb[DU_UPDATE_USERNAME])) != '\0' &&
-			tb[DU_UPDATE_PASSWORD] &&
-			*(blobmsg_get_string(tb[DU_UPDATE_PASSWORD])) != '\0') {
-			char *url = convert_url(blobmsg_get_string(tb[DU_UPDATE_URL]), blobmsg_get_string(tb[DU_UPDATE_USERNAME]), blobmsg_get_string(tb[DU_UPDATE_PASSWORD]));
-			snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", url);
-		} else
-			snprintf(command, sizeof(command), "opkg install %s 2>/dev/null", blobmsg_get_string(tb[DU_UPDATE_URL]));
-	}
-
-	memset(&bb,0,sizeof(struct blob_buf));
+	memset(&bb, 0, sizeof(struct blob_buf));
 	blob_buf_init(&bb, 0);
 
-	if ((log = popen(command, "r"))) {
-		while(fgets(line, sizeof(line), log) != NULL) {
-			if (strstr(line, "Downloading"))
-				i++;
+	char *full_url = generate_full_url(blobmsg_get_string(tb[DU_UPDATE_URL]),
+			blobmsg_get_string(tb[DU_UPDATE_USERNAME]),
+			blobmsg_get_string(tb[DU_UPDATE_PASSWORD]));
 
-			if (strstr(line, "Upgrading")) {
-				sscanf(line, "Upgrading %63s on root from %*s to %63s...", name, version);
-				i++;
-			}
+	char *environment = get_environment_from_map_du_file(blobmsg_get_string(tb[DU_UPDATE_UUID]));
 
-			if (strstr(line, "Configuring"))
-				i++;
-		}
-		pclose(log);
-	}
-	if (i != 3) {
-		blobmsg_add_u8(&bb,"status", false);
-	} else {
-		blobmsg_add_u8(&bb,"status", true);
-		blobmsg_add_string(&bb,"name", name);
+	int err = swmod_install_remove_package(full_url,
+			environment,
+			SWMOD_INSTALL);
 
-		//delete "..." from version string
-		char *p = strstr(version, "...");
-		if (p) *p = '\0';
+	blobmsg_add_u8(&bb, "status", (!err) ? true : false);
 
-		blobmsg_add_string(&bb,"version", version);
+	if (!err) {
+		blobmsg_add_string(&bb,"name", package_name);
+		blobmsg_add_string(&bb,"version", package_version);
 		blobmsg_add_string(&bb,"uuid", blobmsg_get_string(tb[DU_UPDATE_UUID]));
-		if (map_env)
-			blobmsg_add_string(&bb,"environment", map_env);
-		else
-			blobmsg_add_string(&bb,"environment", "OpenWRT_Linux");
-
-		//update version in map_du file
-		swmod_uci_foreach_section("map_du", "deployment", s) {
-			map_uuid = swmod_uci_get_value_by_section(s, "uuid");
-			if (strcmp(map_uuid, blobmsg_get_string(tb[DU_UPDATE_UUID])) == 0) {
-				swmod_uci_set_value_by_section(s, "version", version);
-				break;
-			}
-		}
+		blobmsg_add_string(&bb,"environment", (environment) ? environment : HOST_SYSTEM);
+
+		// Update map file with the new installed package
+		update_corresponding_section_in_map_du_file(package_version,
+				blobmsg_get_string(tb[DU_UPDATE_URL]),
+				blobmsg_get_string(tb[DU_UPDATE_USERNAME]),
+				blobmsg_get_string(tb[DU_UPDATE_PASSWORD]),
+				environment,
+				blobmsg_get_string(tb[DU_UPDATE_UUID]));
 	}
 
 	ubus_send_reply(ctx, req, bb.head);
 	blob_buf_free(&bb);
-
 	return 0;
 }
 
-enum {
-	DU_UNINSTALL_NAME,
-	DU_UNINSTALL_ENV,
-	__DU_UNINSTALL_MAX
-};
-
-static const struct blobmsg_policy du_uninstall_policy[__DU_UNINSTALL_MAX] = {
-	[DU_UNINSTALL_NAME]     = { .name = "name",     .type = BLOBMSG_TYPE_STRING },
-	[DU_UNINSTALL_ENV]     = { .name = "environment",     .type = BLOBMSG_TYPE_STRING },
-};
-
-static int swmod_du_uninstall(struct ubus_context *ctx, struct ubus_object *obj,
-							 struct ubus_request_data *req, const char *method,
-							 struct blob_attr *msg)
+static int
+swmod_du_uninstall(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
 {
 	struct blob_attr *tb[__DU_UNINSTALL_MAX] = {NULL};
-	char line[512] = {0}, command[512] = {0};
-	DIR *dir;
-	struct dirent *ent;
 	struct blob_buf bb;
-	int found;
-	FILE *log;
 
-	if(blobmsg_parse(du_uninstall_policy, __DU_UNINSTALL_MAX, tb, blob_data(msg), blob_len(msg)))
+	if (blobmsg_parse(du_uninstall_policy, __DU_UNINSTALL_MAX, tb, blob_data(msg), blob_len(msg)))
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
 	if (!tb[DU_UNINSTALL_NAME])
 		return UBUS_STATUS_INVALID_ARGUMENT;
 
-	if (tb[DU_UNINSTALL_ENV]) {
-		found = 0;
-		if (strcmp(blobmsg_get_string(tb[DU_UNINSTALL_ENV]), "OpenWRT_Linux") != 0) {
-			if (isfileexist(LXC_PATH)) {
-				sysfs_foreach_file(LXC_PATH, dir, ent) {
-					if (strcmp(blobmsg_get_string(tb[DU_UNINSTALL_ENV]), ent->d_name) == 0) {
-						found = 1;
-						break;
-					}
-				}
-				if (dir) closedir(dir);
-				if (!found)
-					return UBUS_STATUS_INVALID_ARGUMENT;
-			} else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		}
-		if (found) {
-			if (islxcrunning(blobmsg_get_string(tb[DU_UNINSTALL_ENV])))
-				snprintf(command, sizeof(command), "lxc-attach -n %s -- opkg remove %s 2>/dev/null", blobmsg_get_string(tb[DU_UNINSTALL_ENV]), blobmsg_get_string(tb[DU_UNINSTALL_NAME]));
-			else
-				return UBUS_STATUS_INVALID_ARGUMENT;
-		} else
-			snprintf(command, sizeof(command), "opkg remove %s 2>/dev/null", blobmsg_get_string(tb[DU_UNINSTALL_NAME]));
-	} else {
-		snprintf(command, sizeof(command), "opkg remove %s 2>/dev/null", blobmsg_get_string(tb[DU_UNINSTALL_NAME]));
-	}
-
-	memset(&bb,0,sizeof(struct blob_buf));
+	memset(&bb, 0, sizeof(struct blob_buf));
 	blob_buf_init(&bb, 0);
 
-	if ((log = popen(command, "r"))) {
-		while(fgets(line, sizeof(line), log) != NULL) {
-			if (strstr(line, "Removing package")) {
-				blobmsg_add_u8(&bb,"status", true);
-				break;
-			} else if (strstr(line, "No packages removed")) {
-				blobmsg_add_u8(&bb,"status", false);
-				break;
-			}
-		}
-		pclose(log);
-	}
+	int err = swmod_install_remove_package(blobmsg_get_string(tb[DU_UNINSTALL_NAME]),
+			blobmsg_get_string(tb[DU_UNINSTALL_ENV]),
+			SWMOD_REMOVE);
+
+	blobmsg_add_u8(&bb, "status", (!err) ? true : false);
 
 	ubus_send_reply(ctx, req, bb.head);
 	blob_buf_free(&bb);
 	return 0;
 }
 
-static int swmod_du_list(struct ubus_context *ctx, struct ubus_object *obj,
-				 	 	struct ubus_request_data *req, const char *method,
-						struct blob_attr *msg)
+static int
+swmod_du_list(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
 {
 	struct uci_section *ss = NULL;
 	struct blob_buf bb;
 	void *a, *t;
-	FILE *fp;
 
 	synchronize_deployment_units_with_map_du_file();
-	memset(&bb,0,sizeof(struct blob_buf));
+
+	memset(&bb, 0, sizeof(struct blob_buf));
 	blob_buf_init(&bb, 0);
 
 	a = blobmsg_open_array(&bb, "deployment_unit");
 
-	swmod_uci_foreach_section("map_du", "deployment", ss) {
-		char line[256] = {0}, path[512] = {0}, *spch = NULL;
-		char *soft_name = swmod_uci_get_value_by_section(ss, "name");
-		char *soft_env = swmod_uci_get_value_by_section(ss, "environment");
-		char *soft_uuid = swmod_uci_get_value_by_section(ss, "uuid");
-		char *soft_duid = swmod_uci_get_value_by_section(ss, "duid");
-		char *soft_version = swmod_uci_get_value_by_section(ss, "version");
-		char *soft_url = swmod_uci_get_value_by_section(ss, "url");
+	/* Show Host System */
+	swmod_uci_init(SWMOD_PATH);
+	swmod_uci_foreach_section(SWMOD_MAP_DU, "deployment", ss) {
 
 		t = blobmsg_open_table(&bb, "");
-		blobmsg_add_string(&bb, "name", soft_name);
-		blobmsg_add_string(&bb, "version", soft_version);
-		blobmsg_add_string(&bb, "environment", soft_env);
-		blobmsg_add_string(&bb, "uuid", soft_uuid);
-		blobmsg_add_string(&bb, "duid", soft_duid);
-		if (soft_url && *soft_url != '\0')
-			blobmsg_add_string(&bb, "url", soft_url);
-
-		if (strcmp(soft_env, "OpenWRT_Linux") == 0)
-			snprintf(path, sizeof(path), "%s/%s.control", OPKG_INFO_PATH, soft_name);
-		else
-			snprintf(path, sizeof(path), "%s/%s/rootfs/%s/%s.control", LXC_PATH, soft_env, OPKG_INFO_PATH, soft_name);
-		fp = fopen(path, "r");
-		if ( fp != NULL) {
-			while (fgets(line, 256, fp) != NULL) {
-				if ((spch = strstr(line, "Maintainer:"))) {
-					remove_newline(spch);
-					blobmsg_add_string(&bb, "vendor", spch+12);
-				}
-
-				if ((spch = strstr(line, "Description:"))) {
-					remove_newline(spch);
-					blobmsg_add_string(&bb, "description", spch+14);
-					break;
-				}
-			}
-			fclose(fp);
-		}
 
-		if (strcmp(soft_env, "OpenWRT_Linux") == 0)
-			snprintf(path, sizeof(path), "%s/%s.list", OPKG_INFO_PATH, soft_name);
-		else
-			snprintf(path, sizeof(path), "%s/%s/rootfs/%s/%s.list", LXC_PATH, soft_env, OPKG_INFO_PATH, soft_name);
-		fp = fopen(path, "r");
-		if ( fp != NULL) {
-			char *config = NULL;
-			while (fgets(line, 256, fp) != NULL) {
-				if ((config = strstr(line, "/etc/config/"))) {
-					remove_newline(line);
-					blobmsg_add_string(&bb, "config", config+12);
-					break;
-				}
-			}
-			fclose(fp);
-		}
+		blobmsg_add_string(&bb, "name", swmod_uci_get_value_by_section(ss, "name"));
+		blobmsg_add_string(&bb, "environment", swmod_uci_get_value_by_section(ss, "environment"));
+		blobmsg_add_string(&bb, "uuid", swmod_uci_get_value_by_section(ss, "uuid"));
+		blobmsg_add_string(&bb, "duid", swmod_uci_get_value_by_section(ss, "duid"));
+		blobmsg_add_string(&bb, "url", swmod_uci_get_value_by_section(ss, "url"));
+		blobmsg_add_string(&bb, "version", swmod_uci_get_value_by_section(ss, "version"));
+		blobmsg_add_string(&bb, "config", swmod_uci_get_value_by_section(ss, "config"));
+
+		blobmsg_add_string(&bb, "vendor", ""); //TODO
+		blobmsg_add_string(&bb, "description", ""); //TODO
 
 		blobmsg_close_table(&bb, t);
 	}
+	swmod_uci_fini(SWMOD_MAP_DU);
+
+	/* Show all containers  */
+	const char *lxcpath = NULL;
+
+	if (lxc_is_supported(&lxcpath)) {
+
+		struct dirent *ent;
+		DIR *dir = NULL;
+
+		SYSFS_FOREACH_FILE(lxcpath, dir, ent) {
+
+			if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+				continue;
+
+			char lxc_map_du_path[128] = {0};
+
+			snprintf(lxc_map_du_path, sizeof(lxc_map_du_path), "%s/%s/rootfs%s",
+					lxcpath,
+					ent->d_name,
+					SWMOD_PATH);
+
+			if (!file_exists(lxc_map_du_path))
+				continue;
+
+			swmod_uci_init(lxc_map_du_path);
+			swmod_uci_foreach_section(SWMOD_MAP_DU, "deployment", ss) {
+
+				t = blobmsg_open_table(&bb, "");
+
+				blobmsg_add_string(&bb, "name", swmod_uci_get_value_by_section(ss, "name"));
+				blobmsg_add_string(&bb, "environment", swmod_uci_get_value_by_section(ss, "environment"));
+				blobmsg_add_string(&bb, "uuid", swmod_uci_get_value_by_section(ss, "uuid"));
+				blobmsg_add_string(&bb, "duid", swmod_uci_get_value_by_section(ss, "duid"));
+				blobmsg_add_string(&bb, "url", swmod_uci_get_value_by_section(ss, "url"));
+				blobmsg_add_string(&bb, "version", swmod_uci_get_value_by_section(ss, "version"));
+				blobmsg_add_string(&bb, "config", swmod_uci_get_value_by_section(ss, "config"));
+
+				blobmsg_add_string(&bb, "vendor", ""); //TODO
+				blobmsg_add_string(&bb, "description", ""); //TODO
+
+				blobmsg_close_table(&bb, t);
+			}
+			swmod_uci_fini(SWMOD_MAP_DU);
+		}
+		if (dir) closedir(dir);
+	}
 
 	blobmsg_close_array(&bb, a);
 
@@ -843,287 +530,63 @@ static int swmod_du_list(struct ubus_context *ctx, struct ubus_object *obj,
 	return 0;
 }
 
-static int swmod_eu_list(struct ubus_context *ctx, struct ubus_object *obj,
-				 	 	struct ubus_request_data *req, const char *method,
-						struct blob_attr *msg)
+static void
+populate_execution_unit(void)
 {
-	DIR *dir, *dir_swmod, *dir_lxc;
-	struct dirent *ent, *ent_swmod, *ent_lxc;
-	char fstat[1024] = {0}, fcmd[1024] = {0}, cmdline[256] = {0}, fswmod[1024] = {0}, line[256] = {0}, lxc_proc_path[512] = {0}, lxc_swmod_info[512] = {0};
-	char *package_name;
-	int dgt, pid, ppid, found;
-	unsigned int bsize, vsize;
+	memset(exec_units, '\0', sizeof(exec_units));
+
+	/* Host system */
+	populate_host_system_execution_unit();
+
+	/* Linux containers */
+	populate_lxc_deployment_execution_units(SWMOD_EXECUTION_UNIT);
+}
+
+static int
+swmod_eu_list(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg)
+{;
 	struct blob_buf bb;
 	void *a, *t;
-	FILE *fp;
+	int i, j;
+
+	populate_execution_unit();
 
 	memset(&bb, 0, sizeof(struct blob_buf));
 	blob_buf_init(&bb, 0);
 
 	a = blobmsg_open_array(&bb, "execution_unit");
-	LIST_HEAD(proc_list);
-
-	//parse processes for OpenWRT_Linux
-	sysfs_foreach_file(PROC_PATH, dir, ent) {
-		dgt = ent->d_name[0] - '0';
-		if (dgt < 0 || dgt > 9)
-			continue;
-
-		snprintf(fcmd, sizeof(fcmd), "%s/%s/cmdline", PROC_PATH, ent->d_name);
-		fp = fopen(fcmd, "r");
-		if (fp == NULL)
-			continue;
-
-		if (fgets(cmdline , 255 , fp) == NULL ) {
-			fclose(fp);
-			continue;
-		}
-		fclose(fp);
 
-		snprintf(fstat, sizeof(fstat), "%s/%s/stat", PROC_PATH, ent->d_name);
-		if( access(fstat, F_OK ) == -1 ) {
+	for (i = 0; i < MAX_ENV; i++) {
+		if (!exec_units[i].exists)
 			continue;
-		}
-
-		fp = fopen(fstat, "r");
-		if (fp == NULL)
-			continue;
-		if (fscanf(fp, "%d %*s %*c %d %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %u", &pid, &ppid, &bsize) == 0) {
-			fclose(fp);
-			continue;
-		}
-		fclose(fp);
-
-		if (ppid != 1)
-			continue;
-
-		vsize = bsize / 1024;
 
-		swmod_add_data_to_list(&proc_list, cmdline, pid, vsize);
-	}
-	if (dir) closedir(dir);
-
-	sysfs_foreach_file(OPKG_INFO_PATH, dir_swmod, ent_swmod) {
-		if (strstr(ent_swmod->d_name, "busybox")
-		 || strstr(ent_swmod->d_name, "bcmkernel")
-		 || strstr(ent_swmod->d_name, "juci")
-		 || strstr(ent_swmod->d_name, "lib")
-		 || strstr(ent_swmod->d_name, ".control")
-		 || strstr(ent_swmod->d_name, ".postrm")
-		 || strstr(ent_swmod->d_name, ".prerm")
-		 || strstr(ent_swmod->d_name, ".preinst")
-		 || strstr(ent_swmod->d_name, ".postinst"))
-			continue;
+		for (j = 0; j < MAX_EU; j++) {
+			if (!exec_units[i].eu_exists[j])
+				continue;
 
-		snprintf(fswmod, sizeof(fswmod), "%s/%s", OPKG_INFO_PATH, ent_swmod->d_name);
-		fp = fopen(fswmod, "r");
-		if (fp == NULL)
-			continue;
-		while (fgets(line, 256, fp) != NULL) {
-			found = 0;
-			if (strstr(line, "bin/")) {
-				struct process_res *p;
-				list_for_each_entry(p, &proc_list, list) {
-					if (strstr(line, p->cmd)) {
-						char line[256], path[512], version[64], *spch = NULL, *config = NULL;
-						int disk_space;
-						FILE *fp;
-
-						t = blobmsg_open_table(&bb, "");
-						package_name = get_package_name(ent_swmod->d_name);
-						blobmsg_add_string(&bb, "name", package_name);
-						blobmsg_add_string(&bb, "command", p->cmd);
-						blobmsg_add_u32(&bb, "euid", p->pid);
-						blobmsg_add_u32(&bb, "memory_space", p->vsize);
-						blobmsg_add_string(&bb, "environment", "OpenWRT_Linux");
-
-						snprintf(path, sizeof(path), "%s/%s.control", OPKG_INFO_PATH, package_name);
-						fp = fopen(path, "r");
-						if ( fp != NULL) {
-							while (fgets(line, 256, fp) != NULL) {
-								if(sscanf(line, "Version: %63s", version))
-									blobmsg_add_string(&bb, "version", version);
-
-								if(sscanf(line, "Installed-Size: %d", &disk_space))
-									blobmsg_add_u32(&bb, "disk_space", disk_space);
-
-								if ((spch = strstr(line, "Maintainer:"))) {
-									remove_newline(spch);
-									blobmsg_add_string(&bb, "vendor", spch+12);
-								}
-
-								if ((spch = strstr(line, "Description:"))) {
-									remove_newline(spch);
-									blobmsg_add_string(&bb, "description", spch+14);
-									break;
-								}
-							}
-							fclose(fp);
-						}
-
-						snprintf(path, sizeof(path), "%s/%s.list", OPKG_INFO_PATH, package_name);
-						fp = fopen(path, "r");
-						if ( fp != NULL) {
-							while (fgets(line, 256, fp) != NULL) {
-								if ((config = strstr(line, "/etc/config/"))) {
-									remove_newline(line);
-									blobmsg_add_string(&bb, "config", config+12);
-									break;
-								}
-							}
-							fclose(fp);
-						}
-
-						blobmsg_close_table(&bb, t);
-						found = 1;
-						break;
-					}
-				}
-			}
-			if (found)
-				break;
-		}
-		fclose(fp);
-	}
-	if (dir_swmod) closedir(dir_swmod);
+			t = blobmsg_open_table(&bb, "");
 
-	//parse processes for linux containers
-	if (isfileexist(LXC_PATH)) {
-		sysfs_foreach_file(LXC_PATH, dir_lxc, ent_lxc) {
-			if ((strstr(ent_lxc->d_name, ".")) || (!islxcrunning(ent_lxc->d_name)))
-				continue;
+			blobmsg_add_string(&bb, "name", exec_units[i].name[j]);
+			blobmsg_add_string(&bb, "command", exec_units[i].command[j]);
+			blobmsg_add_string(&bb, "vendor", exec_units[i].vendor[j]);
+			blobmsg_add_string(&bb, "config", exec_units[i].config[j]);
+			blobmsg_add_string(&bb, "version", exec_units[i].version[j]);
+			blobmsg_add_string(&bb, "description", exec_units[i].description[j]);
+			blobmsg_add_string(&bb, "environment", exec_units[i].environment[j]);
+			blobmsg_add_u32(&bb, "euid", exec_units[i].euid[j]);
+			blobmsg_add_u32(&bb, "disk_space", exec_units[i].disk_space[j]);
+			blobmsg_add_u32(&bb, "memory_space", exec_units[i].memory_space[j]);
 
-			snprintf(lxc_proc_path, sizeof(lxc_swmod_info), "%s/%s/rootfs/proc", LXC_PATH, ent_lxc->d_name);
-			sysfs_foreach_file(lxc_proc_path, dir, ent) {
-				dgt = ent->d_name[0] - '0';
-				if (dgt < 0 || dgt > 9)
-					continue;
-
-				snprintf(fcmd, sizeof(fcmd), "%s/%s/rootfs/proc/%s/cmdline", LXC_PATH, ent_lxc->d_name, ent->d_name);
-				fp = fopen(fcmd, "r");
-				if (fp == NULL)
-					continue;
-				if ( fgets (cmdline , 255 , fp) == NULL ) {
-					fclose(fp);
-					continue;
-				}
-				fclose(fp);
-
-				snprintf(fstat, sizeof(fstat), "%s/%s/rootfs/proc/%s/stat", LXC_PATH, ent_lxc->d_name, ent->d_name);
-				if( access(fstat, F_OK ) == -1 ) {
-					continue;
-				}
-
-				fp = fopen(fstat, "r");
-				if (fp == NULL)
-					continue;
-				if (fscanf(fp, "%d %*s %*c %d %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %u", &pid, &ppid, &bsize) == 0) {
-					fclose(fp);
-					continue;
-				}
-				fclose(fp);
-
-				if (ppid != 1)
-					continue;
-
-				vsize = bsize / 1024;
-				swmod_add_data_to_list(&proc_list, cmdline, pid, vsize);
-			}
-			if (dir) closedir(dir);
-
-			snprintf(lxc_swmod_info, sizeof(lxc_swmod_info), "%s/%s/rootfs%s", LXC_PATH, ent_lxc->d_name, OPKG_INFO_PATH);
-			sysfs_foreach_file(lxc_swmod_info, dir_swmod, ent_swmod) {
-				if (strstr(ent_swmod->d_name, "busybox")
-				 || strstr(ent_swmod->d_name, "bcmkernel")
-				 || strstr(ent_swmod->d_name, "juci")
-				 || strstr(ent_swmod->d_name, "lib")
-				 || strstr(ent_swmod->d_name, ".control")
-				 || strstr(ent_swmod->d_name, ".postrm")
-				 || strstr(ent_swmod->d_name, ".prerm")
-				 || strstr(ent_swmod->d_name, ".preinst")
-				 || strstr(ent_swmod->d_name, ".postinst"))
-					continue;
-
-				snprintf(fswmod, sizeof(fswmod), "%s/%s/rootfs%s/%s", LXC_PATH, ent_lxc->d_name, OPKG_INFO_PATH, ent_swmod->d_name);
-				fp = fopen(fswmod, "r");
-				if (fp == NULL)
-					continue;
-				while (fgets(line, 256, fp) != NULL) {
-					found = 0;
-					if (strstr(line, "bin/")) {
-						struct process_res *p;
-						list_for_each_entry(p, &proc_list, list) {
-							if (strstr(line, p->cmd)) {
-								char line[256], path[512], version[64], *spch = NULL, *config = NULL;
-								int disk_space;
-								FILE *fp;
-
-								t = blobmsg_open_table(&bb, "");
-								package_name = get_package_name(ent_swmod->d_name);
-								blobmsg_add_string(&bb, "name", package_name);
-								blobmsg_add_string(&bb, "command", p->cmd);
-								blobmsg_add_u32(&bb, "euid", p->pid);
-								blobmsg_add_u32(&bb, "memory_space", p->vsize);
-								blobmsg_add_string(&bb, "environment", ent_lxc->d_name);
-
-								snprintf(path, sizeof(path), "%s/%s/rootfs%s/%s.control", LXC_PATH, ent_lxc->d_name, OPKG_INFO_PATH, package_name);
-								fp = fopen(path, "r");
-								if ( fp != NULL) {
-									while (fgets(line, 256, fp) != NULL) {
-										if(sscanf(line, "Version: %63s", version))
-											blobmsg_add_string(&bb, "version", version);
-
-										if(sscanf(line, "Installed-Size: %d", &disk_space))
-											blobmsg_add_u32(&bb, "disk_space", disk_space);
-
-										if ((spch = strstr(line, "Maintainer:"))) {
-											remove_newline(spch);
-											blobmsg_add_string(&bb, "vendor", spch+12);
-										}
-
-										if ((spch = strstr(line, "Description:"))) {
-											remove_newline(spch);
-											blobmsg_add_string(&bb, "description", spch+14);
-											break;
-										}
-									}
-									fclose(fp);
-								}
-
-								snprintf(path, sizeof(path), "%s/%s/rootfs%s/%s.list", LXC_PATH, ent_lxc->d_name, OPKG_INFO_PATH, package_name);
-								fp = fopen(path, "r");
-								if ( fp != NULL) {
-									while (fgets(line, 256, fp) != NULL) {
-										if ((config = strstr(line, "/etc/config/"))) {
-											remove_newline(line);
-											blobmsg_add_string(&bb, "config", config+12);
-											break;
-										}
-									}
-									fclose(fp);
-								}
-
-								blobmsg_close_table(&bb, t);
-								found = 1;
-								break;
-							}
-						}
-					}
-					if (found)
-						break;
-				}
-				fclose(fp);
-			}
-			if (dir_swmod) closedir(dir_swmod);
+			blobmsg_close_table(&bb, t);
 		}
-		if (dir_lxc) closedir(dir_lxc);
 	}
 
 	blobmsg_close_array(&bb, a);
 
 	ubus_send_reply(ctx, req, bb.head);
 	blob_buf_free(&bb);
-	swmod_free_data_from_list(&proc_list);
 	return 0;
 }
 
@@ -1147,22 +610,26 @@ static struct ubus_object swmod_object = {
 	.n_methods = ARRAY_SIZE(swmod_object_methods),
 };
 
-static void swmod_init(struct ubus_context *ctx)
+static int swmod_init(struct ubus_context *ctx)
 {
 	int ret;
 
 	ret = ubus_add_object(ctx, &swmod_object);
 	if (ret)
-		fprintf(stderr, "Failed to publish '%s' object : %s\n", swmod_object.name, ubus_strerror(ret));
+		fprintf(stderr, "Failed to publish '%s' object : %s\n",
+				swmod_object.name,
+				ubus_strerror(ret));
+
+	return ret;
 }
 
 int main(void)
 {
 	const char *ubus_socket = NULL;
 	struct ubus_context *ctx = NULL;
+	int ret;
 
 	uloop_init();
-	swmod_uci_init();
 
 	ctx = ubus_connect(ubus_socket);
 	if (!ctx) {
@@ -1170,14 +637,16 @@ int main(void)
 		return -1;
 	}
 
-	synchronize_deployment_units_with_map_du_file();
 	ubus_add_uloop(ctx);
-	swmod_init(ctx);
+
+	ret = swmod_init(ctx);
+	if (ret)
+		goto out;
 
 	uloop_run();
+out:
 	ubus_free(ctx);
 	uloop_done();
-	swmod_uci_fini();
 
 	return 0;
 }
diff --git a/swmod.h b/swmod.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce442380b97015a9c13071231e046e83dc19065b
--- /dev/null
+++ b/swmod.h
@@ -0,0 +1,63 @@
+/*
+ * swmod.h: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef SWMOD_H
+#define SWMOD_H
+
+#include <stdbool.h>
+
+#define HOST_SYSTEM "OpenWRT_Linux"
+#define MAX_ENV 8 //Max Environment
+#define MAX_EU 256 //Max Execution Unit
+
+typedef struct {
+	bool exists;
+	char status[32]; //Status
+	char name[32]; //Name
+	char type[64]; //Type
+	char vendor[128]; //Vendor
+	char version[16]; //Version
+	unsigned long allocated_disk_space; //AllocatedDiskSpace
+	unsigned long available_disk_space; //AvailableDiskSpace
+	unsigned long allocated_memory; //AllocatedMemory
+	unsigned long available_memory; //AvailableMemory
+} ExecEnv;
+
+typedef struct {
+	bool exists;
+	bool eu_exists[MAX_EU];
+	char name[MAX_EU][32]; // //Execution Unit Name
+	char command[MAX_EU][32]; //Execution Unit Command
+	char vendor[MAX_EU][128]; //Execution Unit Vendor
+	char config[MAX_EU][32]; //Config File
+	char version[MAX_EU][32]; //Version
+	char description[MAX_EU][1024]; //Description
+	char environment[MAX_EU][32]; //Environment Name
+	int euid[MAX_EU]; //EUID
+	int disk_space[MAX_EU]; //DiskSpaceInUse
+	int memory_space[MAX_EU]; //MemoryInUse
+} ExecUnit;
+
+extern ExecEnv environments[MAX_ENV];
+extern ExecUnit exec_units[MAX_ENV];
+
+#endif //SWMOD_H
diff --git a/swmod_host.c b/swmod_host.c
new file mode 100644
index 0000000000000000000000000000000000000000..0ac1ff0dfc09225ff41885549c5f141a131572b7
--- /dev/null
+++ b/swmod_host.c
@@ -0,0 +1,221 @@
+/*
+ * swmod_host.c: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/sysinfo.h>
+#include <sys/utsname.h>
+
+#include "tools.h"
+#include "swmod_opkg.h"
+#include "swmod_uci.h"
+#include "swmod.h"
+
+void populate_host_system_environment(void)
+{
+	environments[0].exists = true;
+	swmod_strncpy(environments[0].name, HOST_SYSTEM, 14);
+	swmod_strncpy(environments[0].status, "Up", 3);
+
+	struct utsname utsname;
+
+	if (uname(&utsname) >= 0) {
+		swmod_strncpy(environments[0].type, utsname.sysname, 64);
+		swmod_strncpy(environments[0].vendor, utsname.nodename, 128);
+		swmod_strncpy(environments[0].version, utsname.release, 16);
+	}
+
+	struct sysinfo sinfo;
+
+	if (sysinfo(&sinfo) == 0) {
+		environments[0].allocated_disk_space = 0; // TODO
+		environments[0].available_disk_space = 0; // TODO
+		environments[0].allocated_memory = (sinfo.totalram / 1024);
+		environments[0].available_memory = (sinfo.freeram / 1024);
+	}
+}
+
+static void package_list_installed_callback(pkg_t *pkg, void *data)
+{
+	char *environment = (char *)data;
+
+	if (pkg->state_status == SS_INSTALLED) {
+		struct uci_section *s = NULL;
+		bool found = false;
+		static int incr = 0;
+
+		swmod_uci_foreach_section(SWMOD_MAP_DU, "deployment", s) {
+			char *map_name = swmod_uci_get_value_by_section(s, "name");
+
+			/* Check if package name exists */
+			if (strcmp(map_name, pkg->name) == 0) {
+				found = true;
+				break;
+			}
+		}
+		if (found)
+			return;
+
+		struct uci_section *new_s = swmod_uci_add_section(SWMOD_MAP_DU, "deployment");
+
+		char *version = NULL, *config = NULL;
+
+		/* Get version and config from package name */
+		swmod_opkg_find_package_with_version_and_config(pkg->name, &version, &config);
+
+		/* Generate UUID */
+		char *uuid = generate_uuid();
+
+		/* Generate DUID */
+		char *duid = generate_duid(true, incr);
+		incr++;
+
+		swmod_uci_set_value_by_section(new_s, "name", pkg->name);
+		swmod_uci_set_value_by_section(new_s, "version", (version) ? version : "");
+		swmod_uci_set_value_by_section(new_s, "config", (config) ? version : "");
+		swmod_uci_set_value_by_section(new_s, "uuid", uuid);
+		swmod_uci_set_value_by_section(new_s, "duid", duid);
+		swmod_uci_set_value_by_section(new_s, "environment", environment);
+
+		/* Freed all allocated memory */
+		FREE(uuid);
+		FREE(duid);
+		FREE(version);
+		FREE(config);
+	}
+}
+
+void populate_host_system_deployment_unit(void)
+{
+	if (swmod_opkg_new())
+		return;
+
+	if (swmod_uci_init(SWMOD_PATH)) {
+		swmod_opkg_free();
+		return;
+	}
+
+	struct uci_section *s = NULL, *stmp = NULL;
+
+	swmod_uci_foreach_section_safe(SWMOD_MAP_DU, "deployment", stmp, s) {
+		char *map_du_name = swmod_uci_get_value_by_section(s, "name");
+
+		/* Check package name exists, if no => remove the section */
+		if (!swmod_opkg_find_package(map_du_name))
+			swmod_uci_delete_by_section(s, NULL, NULL);
+	}
+
+	opkg_list_packages(package_list_installed_callback, HOST_SYSTEM);
+
+	swmod_uci_fini(SWMOD_MAP_DU);
+
+	swmod_opkg_free();
+}
+
+void populate_host_system_execution_unit(void)
+{
+	if (swmod_opkg_new())
+		return;
+
+	LIST_HEAD(proc_list);
+
+	populate_active_processes(&proc_list);
+
+	bool process_found, bin_found;
+	pkg_vec_t *all;
+	int i, nbr = 0;
+
+	all = pkg_vec_alloc();
+	pkg_hash_fetch_available(all);
+	exec_units[0].exists = true;
+
+	for (i = 0; i < all->len; i++) {
+		pkg_t *pkg = all->pkgs[i];
+
+		str_list_elt_t *iter;
+		str_list_t *files = pkg_get_installed_files(pkg);
+		for (iter = str_list_first(files); iter; iter = str_list_next(files, iter)) {
+
+			bin_found = false;
+			char *spch = NULL;
+			if ((spch = strstr((char *)iter->data, "bin/"))) {
+
+				bin_found = true;
+				process_found = false;
+				struct process_res *p;
+				list_for_each_entry(p, &proc_list, list) {
+
+					if (strstr(p->cmd, spch)) {
+
+						char line[1024], path[512], *spch = NULL, *config = NULL;
+						int disk_space;
+
+						exec_units[0].eu_exists[nbr] = true;
+						swmod_strncpy(exec_units[0].name[nbr], pkg->name, 32);
+						swmod_strncpy(exec_units[0].command[nbr], p->cmd, 32);
+						swmod_strncpy(exec_units[0].environment[nbr], HOST_SYSTEM, 14);
+						exec_units[0].euid[nbr] = p->pid;
+						exec_units[0].memory_space[nbr] = p->vsize;
+
+						char *version = pkg_version_str_alloc(pkg);
+						swmod_strncpy(exec_units[0].version[nbr], version, 32);
+						FREE(version);
+
+						snprintf(path, sizeof(path), "%s/%s.control", OPKG_INFO_PATH, pkg->name);
+						FILE *fp = fopen(path, "r");
+						if ( fp != NULL) {
+							while (fgets(line, sizeof(line), fp) != NULL) {
+								if (sscanf(line, "Installed-Size: %d", &disk_space))
+									exec_units[0].disk_space[nbr] = disk_space;
+
+								if ((spch = strstr(line, "Description:"))) {
+									remove_new_line(spch);
+									swmod_strncpy(exec_units[0].description[nbr], spch+14, 1024);
+									break;
+								}
+							}
+							fclose(fp);
+						}
+
+						swmod_strncpy(exec_units[0].vendor[nbr], "", 128);  // TODO
+						swmod_strncpy(exec_units[0].config[nbr], "", 32); // TODO
+
+						nbr++;
+						process_found = true;
+						break;
+					}
+				}
+				if (process_found)
+					break;
+
+			}
+			if (bin_found)
+				break;
+		}
+	}
+
+	pkg_vec_free(all);
+
+	swmod_opkg_free();
+
+	swmod_free_data_from_list(&proc_list);
+}
diff --git a/swmod_host.h b/swmod_host.h
new file mode 100644
index 0000000000000000000000000000000000000000..275fcd4df60ccffba16e5576545d5396c81d0f2b
--- /dev/null
+++ b/swmod_host.h
@@ -0,0 +1,30 @@
+/*
+ * swmod_host.h: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef HOST_H
+#define HOST_H
+
+void populate_host_system_environment(void);
+void populate_host_system_deployment_unit(void);
+void populate_host_system_execution_unit(void);
+
+#endif //HOST_H
diff --git a/swmod_lxc.c b/swmod_lxc.c
new file mode 100644
index 0000000000000000000000000000000000000000..9653c4c5f33cca0b03c14cde66049e6595ef69f6
--- /dev/null
+++ b/swmod_lxc.c
@@ -0,0 +1,502 @@
+/*
+ * swmod_lxc.c: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/sysinfo.h>
+#include <sys/utsname.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "tools.h"
+#include "swmod_uci.h"
+#include "swmod_opkg.h"
+#include "swmod.h"
+
+#define LXC_CONFIG_PATH "/etc/lxc/lxc.conf"
+#define LXC_PATH "lxc.lxcpath"
+
+#define LXC_ATTACH_OUT(fmt, ...) do { \
+	fprintf(stdout, fmt, ##__VA_ARGS__); fflush(NULL); \
+} while (0)
+
+static char lxc_attach_result[512] = {0};
+
+typedef struct lxc_attach_args {
+	const char *value;
+	int action;
+} lxc_attach_args;
+
+const char *get_lxc_path_from_config(void)
+{
+	return lxc_get_global_config_item(LXC_PATH);
+}
+
+bool lxc_is_supported(const char **lxcpath)
+{
+	if (!file_exists(LXC_CONFIG_PATH))
+		return false;
+
+	*lxcpath = get_lxc_path_from_config();
+
+	if (!(*lxcpath) || !file_exists(*lxcpath))
+		return false;
+
+	return true;
+}
+
+static int lxc_attach_func(struct lxc_container *ct, lxc_attach_exec_t exec_function, lxc_attach_args *command)
+{
+	pid_t pid;
+	int ret, pipefd[2];
+	lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+
+	ret = pipe(pipefd);
+	if (ret < 0)
+		return ret;
+
+	attach_options.stdout_fd = pipefd[1];
+
+	ret = ct->attach(ct, exec_function, command, &attach_options, &pid);
+	if (ret < 0)
+		goto err1;
+
+	ret = read(pipefd[0], lxc_attach_result, sizeof(lxc_attach_result)-1);
+	if (ret < 0)
+		goto err2;
+
+	lxc_attach_result[ret] = '\0';
+	ret = 0;
+
+err2:
+	wait_for_pid(pid);
+
+err1:
+	close(pipefd[0]);
+	close(pipefd[1]);
+
+	return ret;
+}
+
+/************************** Execution Environments **************************/
+static int lxc_attach_run_env_func(void *args)
+{
+	struct utsname utsname;
+	char type[64] = {0}, vendor[128] = {0}, version[16] = {0};
+
+	if (uname(&utsname) >= 0) {
+		swmod_strncpy(type, utsname.sysname, 64);
+		swmod_strncpy(vendor, utsname.nodename, 128);
+		swmod_strncpy(version, utsname.release, 16);
+	}
+
+	struct sysinfo sinfo;
+	unsigned long alloc_mem = 0, avail_mem = 0;
+
+	if (sysinfo(&sinfo) == 0) {
+		alloc_mem = (sinfo.totalram / 1024);
+		avail_mem = (sinfo.freeram / 1024);
+	}
+
+	/* lxc_attach_result buffer format */
+	/* type=<ENV_TYPE> vendor=<ENV_VENDOR> version=<ENV_VERSION>
+	 *  alloc_mem=<ENV_ALLOCATED_MEMORY> avail_mem=<ENV_AVAILABLE_MEMORY> */
+	LXC_ATTACH_OUT("type=%s vendor=%s version=%s alloc_mem=%lu avail_mem=%lu",
+			type,
+			vendor,
+			version,
+			alloc_mem,
+			avail_mem);
+
+	return 0;
+}
+
+void populate_lxc_environment(void)
+{
+	const char *lxcpath = NULL;
+
+	if (!lxc_is_supported(&lxcpath))
+		return;
+
+	struct lxc_container **clist;
+	int i, lxc_nbr;
+
+	lxc_nbr = list_all_containers(lxcpath, NULL, &clist);
+
+	for (i = 0; i < lxc_nbr; i++) {
+		struct lxc_container *ct = clist[i];
+
+		environments[i+1].exists = true;
+		swmod_strncpy(environments[i+1].name, ct->name, 32);
+		swmod_strncpy(environments[i+1].status, (ct->is_running(ct)) ? "Up" : "Disabled", 9);
+		swmod_strncpy(environments[i+1].type, "Linux Container", 16);
+
+		if (!ct->is_running(ct)) {
+			lxc_container_put(ct);
+			continue;
+		}
+
+		int ret = lxc_attach_func(ct, lxc_attach_run_env_func, NULL);
+		if (ret >= 0) {
+			/* lxc_attach_result buffer format */
+			/* type=<ENV_TYPE> vendor=<ENV_VENDOR> version=<ENV_VERSION>
+			 *  alloc_mem=<ENV_ALLOCATED_MEMORY> avail_mem=<ENV_AVAILABLE_MEMORY> */
+
+			sscanf(lxc_attach_result, "type=%64s vendor=%128s version=%16s alloc_mem=%lu avail_mem=%lu",
+					environments[i+1].type,
+					environments[i+1].vendor,
+					environments[i+1].version,
+					&(environments[i+1].allocated_memory),
+					&(environments[i+1].available_memory));
+
+			environments[i+1].allocated_disk_space = 0; // TODO
+			environments[i+1].available_disk_space = 0; // TODO
+		}
+
+		lxc_container_put(ct);
+	}
+
+	if (lxc_nbr > 0)
+		FREE(clist);
+}
+
+/************************** Deployment/Execution Unit **************************/
+static void package_list_installed_callback(pkg_t *pkg, void *data)
+{
+	char *environment = (char *)data;
+
+	if (pkg->state_status == SS_INSTALLED) {
+		struct uci_section *s = NULL;
+		bool found = false;
+		static int incr = 0;
+
+		swmod_uci_foreach_section(SWMOD_MAP_DU, "deployment", s) {
+			char *map_name = swmod_uci_get_value_by_section(s, "name");
+
+			/* Check if package name exists */
+			if (strcmp(map_name, pkg->name) == 0) {
+				found = true;
+				break;
+			}
+		}
+		if (found)
+			return;
+
+		struct uci_section *new_s = swmod_uci_add_section(SWMOD_MAP_DU, "deployment");
+
+		char *version = NULL, *config = NULL;
+
+		/* Get version and config from package name */
+		swmod_opkg_find_package_with_version_and_config(pkg->name, &version, &config);
+
+		/* Generate UUID */
+		char *uuid = generate_uuid();
+
+		/* Generate DUID */
+		char *duid = generate_duid(true, incr);
+		incr++;
+
+		swmod_uci_set_value_by_section(new_s, "name", pkg->name);
+		swmod_uci_set_value_by_section(new_s, "version", (version) ? version : "");
+		swmod_uci_set_value_by_section(new_s, "config", (config) ? version : "");
+		swmod_uci_set_value_by_section(new_s, "uuid", uuid);
+		swmod_uci_set_value_by_section(new_s, "duid", duid);
+		swmod_uci_set_value_by_section(new_s, "environment", environment);
+
+		/* Freed all allocated memory */
+		FREE(uuid);
+		FREE(duid);
+		FREE(version);
+		FREE(config);
+	}
+}
+
+static int lxc_attach_run_deployment_unit_func(void *args)
+{
+	lxc_attach_args *data = (lxc_attach_args *)args;
+
+	if (!data || *(data->value) == '\0')
+		return -1;
+
+	if (swmod_opkg_new())
+		return -1;
+
+	if (swmod_uci_init(SWMOD_PATH)) {
+		swmod_opkg_free();
+		return -1;
+	}
+
+	struct uci_section *s = NULL, *stmp = NULL;
+
+	swmod_uci_foreach_section_safe(SWMOD_MAP_DU, "deployment", stmp, s) {
+		char *map_du_name = swmod_uci_get_value_by_section(s, "name");
+
+		/* Check package name exists, if no => remove the section */
+		if (!swmod_opkg_find_package(map_du_name))
+			swmod_uci_delete_by_section(s, NULL, NULL);
+	}
+
+	opkg_list_packages(package_list_installed_callback, (void *)data->value);
+
+	swmod_uci_fini(SWMOD_MAP_DU);
+
+	swmod_opkg_free();
+
+	LXC_ATTACH_OUT("populate deployment unit: done");
+
+	return 0;
+}
+
+static int lxc_attach_run_execution_unit_func(void *args)
+{
+	lxc_attach_args *data = (lxc_attach_args *)args;
+
+	if (!data || *(data->value) == '\0')
+		return -1;
+
+	if (swmod_opkg_new())
+		return -1;
+
+	if (swmod_uci_init(SWMOD_PATH)) {
+		swmod_opkg_free();
+		return -1;
+	}
+
+	LIST_HEAD(proc_list);
+
+	populate_active_processes(&proc_list);
+
+	char path[32];
+	snprintf(path, sizeof(path), "%s%s", SWMOD_PATH, SWMOD_MAP_EU);
+	remove(path); //remove map_eu file
+	create_file(path); //cretae new empty map_eu file
+
+	bool process_found, bin_found;
+	pkg_vec_t *all;
+	int i, nbr = 0;
+
+	all = pkg_vec_alloc();
+	pkg_hash_fetch_available(all);
+
+	for (i = 0; i < all->len; i++) {
+		pkg_t *pkg = all->pkgs[i];
+
+		str_list_elt_t *iter;
+		str_list_t *files = pkg_get_installed_files(pkg);
+		for (iter = str_list_first(files); iter; iter = str_list_next(files, iter)) {
+
+			bin_found = false;
+			char *spch = NULL;
+			if ((spch = strstr((char *)iter->data, "bin/"))) {
+
+				bin_found = true;
+				process_found = false;
+				struct process_res *p;
+				list_for_each_entry(p, &proc_list, list) {
+
+					if (strstr(p->cmd, spch)) {
+
+						char line[1024], description[1024], path[512], version[32];
+						char *spch = NULL, *config = NULL;
+						int disk_space;
+
+						char *pkg_version = pkg_version_str_alloc(pkg);
+						swmod_strncpy(version, pkg_version, 32);
+						FREE(pkg_version);
+
+						snprintf(path, sizeof(path), "%s/%s.control", OPKG_INFO_PATH, pkg->name);
+						FILE *fp = fopen(path, "r");
+						if ( fp != NULL) {
+							while (fgets(line, sizeof(line), fp) != NULL) {
+								sscanf(line, "Installed-Size: %d", &disk_space);
+
+								if ((spch = strstr(line, "Description:"))) {
+									remove_new_line(spch);
+									swmod_strncpy(description, spch+14, 1024);
+									break;
+								}
+							}
+							fclose(fp);
+						}
+
+						char buf_pid[16], buf_vsize[16], buf_disk_space[16];
+
+						snprintf(buf_pid, sizeof(buf_pid), "%d", p->pid);
+						snprintf(buf_vsize, sizeof(buf_vsize), "%d", p->vsize);
+						snprintf(buf_disk_space, sizeof(buf_disk_space), "%d", disk_space);
+
+						struct uci_section *new_s = swmod_uci_add_section(SWMOD_MAP_EU, "exec_unit");
+						swmod_uci_set_value_by_section(new_s, "name", pkg->name);
+						swmod_uci_set_value_by_section(new_s, "command", p->cmd);
+						swmod_uci_set_value_by_section(new_s, "environment", "Linux Container");
+						swmod_uci_set_value_by_section(new_s, "euid", buf_pid);
+						swmod_uci_set_value_by_section(new_s, "memory_space", buf_vsize);
+						swmod_uci_set_value_by_section(new_s, "disk_space", buf_disk_space);
+						swmod_uci_set_value_by_section(new_s, "version", version);
+						swmod_uci_set_value_by_section(new_s, "description", description);
+
+						nbr++;
+						process_found = true;
+						break;
+					}
+				}
+				if (process_found)
+					break;
+
+			}
+
+			if (bin_found)
+				break;
+		}
+	}
+
+	pkg_vec_free(all);
+
+	swmod_uci_fini(SWMOD_MAP_EU);
+
+	swmod_opkg_free();
+
+	swmod_free_data_from_list(&proc_list);
+
+	LXC_ATTACH_OUT("populate execution unit: done");
+
+	return 0;
+}
+
+void populate_lxc_deployment_execution_units(int action)
+{
+	const char *lxcpath = NULL;
+
+	if (!lxc_is_supported(&lxcpath))
+		return;
+
+	struct lxc_container **clist;
+	int i, lxc_nbr;
+
+	lxc_nbr = list_all_containers(lxcpath, NULL, &clist);
+
+	for (i = 0; i < lxc_nbr; i++) {
+		struct lxc_container *ct = clist[i];
+
+		if (!ct->is_running(ct)) {
+			lxc_container_put(ct);
+			goto end;
+		}
+
+		lxc_attach_args command = (lxc_attach_args){.value = ct->name};
+
+		if (action == SWMOD_DEPLOYMENT_UNIT)
+			lxc_attach_func(ct, lxc_attach_run_deployment_unit_func, &command);
+		else if (action == SWMOD_EXECUTION_UNIT)
+			lxc_attach_func(ct, lxc_attach_run_execution_unit_func, &command);
+
+		lxc_container_put(ct);
+	}
+
+end:
+	if (lxc_nbr > 0)
+		FREE(clist);
+}
+
+/************************** Install/Remove **************************/
+static void progress_lxc_cb(const opkg_progress_data_t *progress, void *data)
+{
+	/* lxc_attach_result buffer format */
+	/* pkg_name=<PACKAGE_NAME> pkg_version=<PACKAGE_VERSION> */
+
+	char *version = pkg_version_str_alloc(progress->pkg);
+	LXC_ATTACH_OUT("pkg_name=%s pkg_version=%s", progress->pkg->name, version);
+	FREE(version);
+}
+
+static int lxc_attach_run_install_remove_func(void *args)
+{
+	lxc_attach_args *data = (lxc_attach_args *)args;
+
+	if (swmod_opkg_new())
+		return -1;
+
+	if (!data || *(data->value) == '\0')
+		return -1;
+
+	int err;
+
+	if (data->action == SWMOD_INSTALL)
+		err = opkg_install_package(data->value, progress_lxc_cb, "Installing...");
+	else if (data->action == SWMOD_REMOVE)
+		err = opkg_remove_package(data->value, progress_lxc_cb, "Removing...");
+	else
+		err = -1;
+
+	swmod_opkg_free();
+
+	return err;
+}
+
+int swmod_lxc_install_remove_package(const char *package_path, const char *environment, int action)
+{
+	const char *lxcpath = NULL;
+
+	if (!lxc_is_supported(&lxcpath))
+		return -1;
+
+	struct lxc_container **clist;
+	int i, lxc_nbr, err = -1;
+
+	lxc_nbr = list_all_containers(lxcpath, NULL, &clist);
+
+	for (i = 0; i < lxc_nbr; i++) {
+		struct lxc_container *ct = clist[i];
+
+		if (strcmp(ct->name, environment) != 0) {
+			lxc_container_put(ct);
+			continue;
+		}
+
+		if (!ct->is_running(ct)) {
+			lxc_container_put(ct);
+			goto end;
+		}
+
+		lxc_attach_args lxc_args = (lxc_attach_args){.value = package_path, .action = action};
+		int ret = lxc_attach_func(ct, lxc_attach_run_install_remove_func, &lxc_args);
+		if (ret >= 0) {
+			/* lxc_attach_result buffer format */
+			/* pkg_name=<PACKAGE_NAME> pkg_version=<PACKAGE_VERSION> */
+
+			sscanf(lxc_attach_result, "pkg_name=%64s pkg_version=%64s",
+					package_name,
+					package_version);
+
+			err = 0;
+		}
+
+		lxc_container_put(ct);
+		break;
+	}
+
+end:
+	if (lxc_nbr > 0)
+		FREE(clist);
+
+	return err;
+}
diff --git a/swmod_lxc.h b/swmod_lxc.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee171d29895c131382455364a6c4cfa497639e0b
--- /dev/null
+++ b/swmod_lxc.h
@@ -0,0 +1,32 @@
+/*
+ * swmod_lxc.h: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef LXC_H
+#define LXC_H
+
+bool lxc_is_supported(const char **lxcpath);
+const char *get_lxc_path_from_config(void);
+void populate_lxc_environment(void);
+void populate_lxc_deployment_execution_units(int action);
+int swmod_lxc_install_remove_package(const char *package_path, const char *environment, int action);
+
+#endif //LXC_H
diff --git a/swmod_opkg.c b/swmod_opkg.c
new file mode 100644
index 0000000000000000000000000000000000000000..f4a278b4915791a87074e500355162f9b24b240c
--- /dev/null
+++ b/swmod_opkg.c
@@ -0,0 +1,118 @@
+/*
+ * swmod_opkg.c: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdbool.h>
+
+#include "tools.h"
+#include "swmod.h"
+#include "swmod_uci.h"
+#include "swmod_lxc.h"
+#include "swmod_opkg.h"
+
+char package_name[64] = "";
+char package_version[64] = "";
+
+int swmod_opkg_new(void)
+{
+	if (opkg_new())
+		return -1;
+
+	return 0;
+}
+
+int swmod_opkg_free(void)
+{
+	opkg_free();
+	return 0;
+}
+
+static void progress_callback(const opkg_progress_data_t *progress, void *data)
+{
+	swmod_strncpy(package_name, progress->pkg->name, sizeof(package_name));
+
+	char *version = pkg_version_str_alloc(progress->pkg);
+	swmod_strncpy(package_version, version, sizeof(package_version));
+	FREE(version);
+}
+
+static int swmod_host_system_install_remove_package(const char *package_path, int action)
+{
+	if (swmod_opkg_new())
+		return -1;
+
+	int err;
+
+	if (action == SWMOD_INSTALL)
+		err = opkg_install_package(package_path, progress_callback, "Installing...");
+	else if (action == SWMOD_REMOVE)
+		err = opkg_remove_package(package_path, progress_callback, "Removing...");
+	else
+		err = -1;
+
+	swmod_opkg_free();
+
+	return err;
+}
+
+int swmod_install_remove_package(const char *package_path, const char *environment, int action)
+{
+	if (environment && (strcmp(environment, HOST_SYSTEM) != 0))
+		return swmod_lxc_install_remove_package(package_path, environment, action);
+
+	return swmod_host_system_install_remove_package(package_path, action);
+}
+
+bool swmod_opkg_find_package(const char *package_name)
+{
+	pkg_t *pkg = opkg_find_package(package_name, NULL, NULL, NULL);
+
+	return (pkg) ? true : false;
+}
+
+void swmod_opkg_find_package_with_version_and_config(const char *package_name, char **version, char **config)
+{
+	pkg_t *pkg = opkg_find_package(package_name, NULL, NULL, NULL);
+
+	if (!pkg)
+		return;
+
+	char *pkg_version = pkg_version_str_alloc(pkg);
+	*version = strdup(pkg_version);
+	FREE(pkg_version);
+
+	// for now, we can not use opkg API to read vendor and description and url
+	// so, we will read them from "/usr/lib/opkg/info/*.control" file
+
+	//const char *vendor = pkg_get_string(pkg, PKG_MAINTAINER);
+	//const char *description = pkg_get_string(pkg, PKG_DESCRIPTION);
+
+	char *spch = NULL;
+	str_list_elt_t *iter;
+	str_list_t *files = pkg_get_installed_files(pkg);
+	for (iter = str_list_first(files); iter; iter = str_list_next(files, iter)) {
+		if ((spch = strstr((char *)iter->data, "/etc/config/"))) {
+			remove_new_line(spch);
+			*config = strdup(spch+12);
+			break;
+		}
+	}
+}
diff --git a/swmod_opkg.h b/swmod_opkg.h
new file mode 100644
index 0000000000000000000000000000000000000000..dcb41e4bb0a638aaf55c65e87ba22964ab293c89
--- /dev/null
+++ b/swmod_opkg.h
@@ -0,0 +1,42 @@
+/*
+ * swmod_opkg.h: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __SWMOD_OPKG_H
+#define __SWMOD_OPKG_H
+
+#include <libopkg/opkg.h>
+
+extern char package_name[64];
+extern char package_version[64];
+
+enum swmod_opkg_action_enum {
+	SWMOD_INSTALL,
+	SWMOD_REMOVE
+};
+
+int swmod_opkg_new(void);
+int swmod_opkg_free(void);
+int swmod_install_remove_package(const char *package_path, const char *environment, int action);
+bool swmod_opkg_find_package(const char *package_name);
+void swmod_opkg_find_package_with_version_and_config(const char *package_name, char **version, char **config);
+
+#endif //__SWMOD_OPKG_H
diff --git a/swmod_uci.c b/swmod_uci.c
new file mode 100644
index 0000000000000000000000000000000000000000..cdd66254e45d8a64fb3c62135fcdc9d42a467707
--- /dev/null
+++ b/swmod_uci.c
@@ -0,0 +1,293 @@
+/*
+ * swmod_uci.c: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include "swmod_uci.h"
+
+static struct uci_context *uci_ctx_swmod = NULL;
+
+static int swmod_commit_package(char *package)
+{
+	struct uci_ptr ptr = {0};
+
+	if (uci_lookup_ptr(uci_ctx_swmod, &ptr, package, true) != UCI_OK)
+		return -1;
+
+	if (uci_commit(uci_ctx_swmod, &ptr.p, false) != UCI_OK)
+		return -1;
+
+	return 0;
+}
+
+int swmod_uci_init(const char *conf_path)
+{
+	uci_ctx_swmod = uci_alloc_context();
+	if (!uci_ctx_swmod)
+		return -1;
+
+	uci_set_confdir(uci_ctx_swmod, conf_path);
+
+	return 0;
+}
+
+int swmod_uci_fini(char *package_name)
+{
+	/* Commit package */
+	swmod_commit_package(package_name);
+
+	/* Freed uci context  */
+	if (uci_ctx_swmod)
+		uci_free_context(uci_ctx_swmod);
+
+	return 0;
+}
+
+static bool swmod_uci_validate_section(const char *str)
+{
+	if (!*str)
+		return false;
+
+	for (; *str; str++) {
+		unsigned char c = *str;
+
+		if (isalnum(c) || c == '_')
+			continue;
+
+		return false;
+	}
+
+	return true;
+}
+
+static int swmod_uci_init_ptr(struct uci_ptr *ptr, char *package, char *section, char *option, char *value)
+{
+	memset(ptr, 0, sizeof(struct uci_ptr));
+
+	/* value */
+	if (value)
+		ptr->value = value;
+
+	ptr->package = package;
+	if (!ptr->package)
+		goto error;
+
+	ptr->section = section;
+	if (!ptr->section) {
+		ptr->target = UCI_TYPE_PACKAGE;
+		goto lastval;
+	}
+
+	ptr->option = option;
+	if (!ptr->option) {
+		ptr->target = UCI_TYPE_SECTION;
+		goto lastval;
+	} else
+		ptr->target = UCI_TYPE_OPTION;
+
+lastval:
+	if (ptr->section && !swmod_uci_validate_section(ptr->section))
+		ptr->flags |= UCI_LOOKUP_EXTENDED;
+
+	return 0;
+
+error:
+	return -1;
+}
+
+struct uci_section *swmod_uci_walk_section(char *package, char *section_type, struct uci_section *prev_section)
+{
+	struct uci_ptr ptr;
+	struct uci_element *e;
+	struct uci_section *next_section;
+
+	if (section_type == NULL) {
+		if (prev_section) {
+			e = &prev_section->e;
+			if (e->list.next == &prev_section->package->sections)
+				return NULL;
+			e = container_of(e->list.next, struct uci_element, list);
+			next_section = uci_to_section(e);
+			return next_section;
+		} else {
+			if (swmod_uci_init_ptr(&ptr, package, NULL, NULL, NULL))
+				return NULL;
+
+			if (uci_lookup_ptr(uci_ctx_swmod, &ptr, NULL, true) != UCI_OK)
+				return NULL;
+
+			if (ptr.p->sections.next == &ptr.p->sections)
+				return NULL;
+			e = container_of(ptr.p->sections.next, struct uci_element, list);
+			next_section = uci_to_section(e);
+
+			return next_section;
+		}
+	} else {
+		struct uci_list *ul = NULL, *shead = NULL;
+
+		if (prev_section) {
+			ul = &prev_section->e.list;
+			shead = &prev_section->package->sections;
+		} else {
+			if (swmod_uci_init_ptr(&ptr, package, NULL, NULL, NULL))
+				return NULL;
+
+			if (uci_lookup_ptr(uci_ctx_swmod, &ptr, NULL, true) != UCI_OK)
+				return NULL;
+
+			ul = &ptr.p->sections;
+			shead = &ptr.p->sections;
+		}
+		while (ul->next != shead) {
+			e = container_of(ul->next, struct uci_element, list);
+			next_section = uci_to_section(e);
+			if (strcmp(next_section->type, section_type) == 0)
+				return next_section;
+			ul = ul->next;
+		}
+		return NULL;
+	}
+	return NULL;
+}
+
+static struct uci_element *swmod_uci_lookup_list(struct uci_list *list, const char *name)
+{
+	struct uci_element *e;
+
+	uci_foreach_element(list, e) {
+		if (!strcmp(e->name, name))
+			return e;
+	}
+
+	return NULL;
+}
+
+static int swmod_uci_lookup_ptr_by_section(struct uci_ptr *ptr, struct uci_section *section, char *option, char *value)
+{
+	struct uci_element *e;
+	memset(ptr, 0, sizeof(struct uci_ptr));
+
+	ptr->package = section->package->e.name;
+	ptr->section = section->e.name;
+	ptr->option = option;
+	ptr->value = value;
+	ptr->flags |= UCI_LOOKUP_DONE;
+
+	ptr->p = section->package;
+	ptr->s = section;
+
+	if (ptr->option) {
+		e = swmod_uci_lookup_list(&ptr->s->options, ptr->option);
+		if (!e)
+			return UCI_OK;
+		ptr->o = uci_to_option(e);
+		ptr->last = e;
+		ptr->target = UCI_TYPE_OPTION;
+	} else {
+		ptr->last = &ptr->s->e;
+		ptr->target = UCI_TYPE_SECTION;
+	}
+
+	ptr->flags |= UCI_LOOKUP_COMPLETE;
+
+	return UCI_OK;
+}
+
+char *swmod_uci_get_value_by_section(struct uci_section *section, char *option)
+{
+	struct uci_ptr ptr;
+	char *val = "";
+
+	if (swmod_uci_lookup_ptr_by_section(&ptr, section, option, NULL) != UCI_OK)
+		return val;
+
+	if (!ptr.o)
+		return val;
+
+	if (ptr.o->v.string)
+		return ptr.o->v.string;
+	else
+		return val;
+}
+
+char *swmod_uci_set_value_by_section(struct uci_section *section, char *option, char *value)
+{
+	struct uci_ptr ptr;
+
+	if (section == NULL)
+		return "";
+
+	if (swmod_uci_lookup_ptr_by_section(&ptr, section, option, value) != UCI_OK)
+		return "";
+
+	if (uci_set(uci_ctx_swmod, &ptr) != UCI_OK)
+		return "";
+
+	if (uci_save(uci_ctx_swmod, ptr.p) != UCI_OK)
+		return "";
+
+	if (ptr.o && ptr.o->v.string)
+		return ptr.o->v.string;
+
+	return "";
+}
+
+struct uci_section *swmod_uci_add_section(char *package, char *section_type)
+{
+	struct uci_ptr ptr;
+	struct uci_section *s = NULL;
+
+	if (swmod_uci_init_ptr(&ptr, package, NULL, NULL, NULL))
+		return NULL;
+
+	if (uci_lookup_ptr(uci_ctx_swmod, &ptr, NULL, true) != UCI_OK)
+		return NULL;
+
+	if (uci_add_section(uci_ctx_swmod, ptr.p, section_type, &s) != UCI_OK)
+		return NULL;
+
+	if (uci_save(uci_ctx_swmod, ptr.p) != UCI_OK)
+		return NULL;
+
+	return s;
+}
+
+int swmod_uci_delete_by_section(struct uci_section *section, char *option, char *value)
+{
+	struct uci_ptr ptr = {0};
+
+	if (section == NULL)
+		return -1;
+
+	if (swmod_uci_lookup_ptr_by_section(&ptr, section, option, value) != UCI_OK)
+		return -1;
+
+	if (uci_delete(uci_ctx_swmod, &ptr) != UCI_OK)
+		return -1;
+
+	if (uci_save(uci_ctx_swmod, ptr.p) != UCI_OK)
+		return -1;
+
+	return 0;
+}
diff --git a/common.h b/swmod_uci.h
similarity index 52%
rename from common.h
rename to swmod_uci.h
index 74767784e84acdca61d37e86b778335b482fbba7..f7c933dd4d632eeb940237474442654a994ab51e 100644
--- a/common.h
+++ b/swmod_uci.h
@@ -1,7 +1,7 @@
 /*
- * common.h: SWMOD deamon
+ * swmod_uci.h: SWMOD deamon
  *
- * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
  *
  * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
  *
@@ -20,80 +20,31 @@
  * 02110-1301 USA
  */
 
-#ifndef __COMMON_H
-#define __COMMON_H
+#ifndef __SWMOD_UCI_H
+#define __SWMOD_UCI_H
 
-#include <string.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <uuid/uuid.h>
-#include <ctype.h>
-#include <unistd.h>
 #include <uci.h>
-#include <libubox/list.h>
 
-#define SWMOD_PATH "/etc/swmod"
-#define OPKG_INFO_PATH "/usr/lib/opkg/info"
-#define DEPLOYMENT_UNIT_PATH "/etc/swmod/map_du"
-#define PROC_PATH "/proc"
-#define LXC_PATH "/srv/lxc"
-#define LXC_INFO "/usr/bin/lxc-info"
+int swmod_uci_init(const char *conf_path);
+int swmod_uci_fini(char *package_name);
 
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-#endif
-
-#define sysfs_foreach_file(path, dir, ent) \
-	if ((dir = opendir(path)) == NULL) return 0; \
-	while ((ent = readdir (dir)) != NULL) \
-
-#ifndef FREE
-#define FREE(x) do { if(x) {free(x); x = NULL;} } while (0)
-#endif
-
-#define swmod_strncpy(dst, src, size) \
-	do { \
-		strncpy(dst, src, size - 1);\
-		dst[size-1] = '\0';\
-	} while(0)
-
-struct process_res
-{
-	struct list_head list;
-	char *cmd;
-	int pid;
-	unsigned int vsize;
-};
-
-int swmod_uci_init(void);
-int swmod_uci_fini(void);
-struct uci_section *swmod_uci_walk_section(char *package, char *section_type, struct uci_section *prev_section);
 struct uci_section *swmod_uci_add_section(char *package, char *section_type);
 int swmod_uci_delete_by_section(struct uci_section *section, char *option, char *value);
+
 char *swmod_uci_get_value_by_section(struct uci_section *section, char *option);
 char *swmod_uci_set_value_by_section(struct uci_section *section, char *option, char *value);
-char *get_package_name(char *full_name);
-int isfileexist(const char *filepath);
-int synchronize_deployment_units_with_map_du_file(void);
-char *convert_url(char *url, char *username, char *password);
-char *generate_uuid(void);
-char *generate_duid(bool sysnchronise, int number);
-void remove_newline(char *buf);
-int islxcrunning(char *lxc_name);
-void swmod_add_data_to_list(struct list_head *dup_list, char *cmd, int pid, unsigned int vsize);
-void swmod_free_data_from_list(struct list_head *dup_list);
+
+struct uci_section *swmod_uci_walk_section(char *package, char *section_type, struct uci_section *prev_section);
 
 #define swmod_uci_foreach_section(package, section_type, section) \
 	for (section = swmod_uci_walk_section(package, section_type, NULL); \
 		section != NULL; \
 		section = swmod_uci_walk_section(package, section_type, section))
 
-#define swmod_uci_foreach_section_safe(package, section_type, _tmp, section)	\
+#define swmod_uci_foreach_section_safe(package, section_type, _tmp, section) \
 	for(section = swmod_uci_walk_section(package, section_type, NULL), \
 		_tmp = (section) ? swmod_uci_walk_section(package, section_type, section) : NULL; \
 		section != NULL; \
 		section = _tmp, _tmp = (section) ? swmod_uci_walk_section(package, section_type, section) : NULL)
 
-#endif //__COMMON_H
-
+#endif //__SWMOD_UCI_H
diff --git a/tools.c b/tools.c
new file mode 100644
index 0000000000000000000000000000000000000000..609598e444b3ae26b81e4a4d072806cdaf069826
--- /dev/null
+++ b/tools.c
@@ -0,0 +1,267 @@
+/*
+ * tools.c: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <uuid/uuid.h>
+
+#include "swmod_uci.h"
+#include "swmod_opkg.h"
+#include "swmod_host.h"
+#include "swmod_lxc.h"
+#include "tools.h"
+
+#define PROC_PATH "/proc"
+
+bool file_exists(const char *path)
+{
+	struct stat statbuf;
+
+	return stat(path, &statbuf) == 0;
+}
+
+void remove_new_line(char *buf)
+{
+	int len;
+	len = strlen(buf) - 1;
+	if (buf[len] == '\n')
+		buf[len] = 0;
+}
+
+void create_file(const char *path)
+{
+	if (!file_exists(path)) {
+		/*
+		 *File does not exist
+		 */
+		FILE *fp = fopen(path, "w"); // new empty file
+		if (fp)
+			fclose(fp);
+	}
+}
+
+void swmod_strncpy(char *dst, const char *src, size_t n)
+{
+	strncpy(dst, src, n - 1);
+	dst[n - 1] = 0;
+}
+
+char *generate_full_url(char *url, char *username, char *password)
+{
+	if (!username && !password)
+		return url;
+
+	static char buf[512]= {0};
+
+	if (strncmp(url, "http://", 7) == 0)
+		snprintf(buf, sizeof(buf), "http://%s:%s@%s", username, password, url+7);
+	else if (strncmp(url, "ftp://", 6) == 0)
+		snprintf(buf, sizeof(buf), "ftp://%s:%s@%s", username, password, url+6);
+
+	return buf;
+}
+
+char *generate_uuid(void)
+{
+	uuid_t binuuid;
+
+	uuid_generate_random(binuuid);
+	char *uuid = malloc(37);
+	uuid_unparse(binuuid, uuid);
+
+	return uuid;
+}
+
+char *generate_duid(bool sysnchronise, int number)
+{
+	char buf[36] = "0123456789abcdefghijklmnopqrstuvwxyz", euid[16] = {0}, euid_num[8] = {0};
+	int i;
+
+	srand(time(NULL));
+	if (sysnchronise) {
+		for (i = 0; i < 3; i++)
+			euid[i] = buf[rand() % 35];
+		sprintf(euid_num, "%04d", number);
+		strncat(euid, euid_num, 4);
+	} else {
+		for (i = 0; i < 7; i++)
+			euid[i] = buf[rand() % 35];
+	}
+	euid[7] = '\0';
+
+	return strdup(euid);
+}
+
+
+int synchronize_deployment_units_with_map_du_file(void)
+{
+	/* Host System */
+	populate_host_system_deployment_unit();
+
+	/* Linux Container */
+	populate_lxc_deployment_execution_units(SWMOD_DEPLOYMENT_UNIT);
+
+	return 0;
+}
+
+char *get_environment_from_map_du_file(const char *uuid)
+{
+	char *env = NULL;
+
+	swmod_uci_init(SWMOD_PATH);
+	struct uci_section *s = NULL;
+	swmod_uci_foreach_section(SWMOD_MAP_DU, "deployment", s) {
+		char *map_uuid = swmod_uci_get_value_by_section(s, "uuid");
+		if (strcmp(map_uuid, uuid) == 0) {
+			env = swmod_uci_get_value_by_section(s, "environment");
+			break;
+		}
+	}
+	swmod_uci_fini(SWMOD_MAP_DU);
+
+	if (env)
+		return env;
+
+	const char *lxcpath = NULL;
+
+	if (lxc_is_supported(&lxcpath)) {
+
+		struct dirent *ent;
+		DIR *dir = NULL;
+
+		SYSFS_FOREACH_FILE(lxcpath, dir, ent) {
+
+			if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+				continue;
+
+			char lxc_map_du_path[128] = {0};
+
+			snprintf(lxc_map_du_path, sizeof(lxc_map_du_path), "%s/%s/rootfs%s",
+					lxcpath,
+					ent->d_name,
+					SWMOD_PATH);
+
+			if (!file_exists(lxc_map_du_path))
+				continue;
+
+			swmod_uci_init(lxc_map_du_path);
+			swmod_uci_foreach_section(SWMOD_MAP_DU, "deployment", s) {
+				char *map_uuid = swmod_uci_get_value_by_section(s, "uuid");
+				if (strcmp(map_uuid, uuid) == 0) {
+					env = swmod_uci_get_value_by_section(s, "environment");
+					break;
+				}
+			}
+			swmod_uci_fini(SWMOD_MAP_DU);
+		}
+		if (dir) closedir(dir);
+	}
+
+	return env;
+}
+
+void swmod_add_data_to_list(struct list_head *dup_list, char *cmd, int pid, unsigned int vsize)
+{
+	struct process_res *proc = calloc(1, sizeof(struct process_res));
+
+	list_add_tail(&proc->list, dup_list);
+	proc->cmd = strdup(cmd);
+	proc->pid = pid;
+	proc->vsize= vsize;
+}
+
+static void swmod_delete_data_from_list(struct process_res *proc)
+{
+	list_del(&proc->list);
+	FREE(proc->cmd);
+	FREE(proc);
+}
+
+void swmod_free_data_from_list(struct list_head *dup_list)
+{
+	struct process_res *proc;
+	while (dup_list->next != dup_list) {
+		proc = list_entry(dup_list->next, struct process_res, list);
+		swmod_delete_data_from_list(proc);
+	}
+}
+
+int populate_active_processes(struct list_head *dup_list)
+{
+	struct dirent *ent;
+	DIR *dir;
+
+	SYSFS_FOREACH_FILE(PROC_PATH, dir, ent) {
+
+		int dgt = ent->d_name[0] - '0';
+		if (dgt < 0 || dgt > 9)
+			continue;
+
+		char fcmd[32];
+		snprintf(fcmd, sizeof(fcmd), "%s/%s/cmdline", PROC_PATH, ent->d_name);
+		FILE *fp = fopen(fcmd, "r");
+		if (fp == NULL)
+			continue;
+
+		char cmdline[256] = {0};
+		if (fgets(cmdline , sizeof(cmdline)-1 , fp) == NULL) {
+			fclose(fp);
+			continue;
+		}
+		fclose(fp);
+
+		char fstat[32];
+		snprintf(fstat, sizeof(fstat), "%s/%s/stat", PROC_PATH, ent->d_name);
+		if (access(fstat, F_OK ) == -1)
+			continue;
+
+		fp = fopen(fstat, "r");
+		if (fp == NULL)
+			continue;
+
+		unsigned int bsize = 0, vsize = 0;
+		int pid, ppid;
+
+		int ret = fscanf(fp, "%d %*s %*c %d %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %u",
+				&pid,
+				&ppid,
+				&bsize);
+
+		if (ret != 3) {
+			fclose(fp);
+			continue;
+		}
+		fclose(fp);
+
+		if (ppid != 1)
+			continue;
+
+		vsize = bsize / 1024;
+
+		swmod_add_data_to_list(dup_list, cmdline, pid, vsize);
+	}
+	if (dir) closedir(dir);
+
+	return 0;
+}
diff --git a/tools.h b/tools.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad4dbf9a8f3d4f81ef773d56398b5f8568b37550
--- /dev/null
+++ b/tools.h
@@ -0,0 +1,69 @@
+/*
+ * tools.h: SWMOD deamon
+ *
+ * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __TOOLS_H
+#define __TOOLS_H
+
+#include <string.h>
+#include <libubox/list.h>
+
+#define SWMOD_PATH "/etc/swmod/"
+#define OPKG_INFO_PATH "/usr/lib/opkg/info"
+#define SWMOD_MAP_DU "map_du"
+#define SWMOD_MAP_EU "map_eu"
+
+#define SYSFS_FOREACH_FILE(path, dir, ent) \
+	if ((dir = opendir(path)) == NULL) return 0; \
+	while ((ent = readdir (dir)) != NULL) \
+
+#ifndef FREE
+#define FREE(x) do { if(x) {free(x); x = NULL;} } while (0)
+#endif
+
+enum swmod_action_enum {
+	SWMOD_DEPLOYMENT_UNIT,
+	SWMOD_EXECUTION_UNIT
+};
+
+struct process_res
+{
+	struct list_head list;
+	char *cmd;
+	int pid;
+	unsigned int vsize;
+};
+
+bool file_exists(const char *path);
+void remove_new_line(char *buf);
+void create_file(const char *path);
+void swmod_strncpy(char *dst, const char *src, size_t n);
+char *generate_full_url(char *url, char *username, char *password);
+char *generate_uuid(void);
+char *generate_duid(bool sysnchronise, int number);
+int synchronize_deployment_units_with_map_du_file(void);
+char *get_environment_from_map_du_file(const char *uuid);
+void swmod_add_data_to_list(struct list_head *dup_list, char *cmd, int pid, unsigned int vsize);
+void swmod_free_data_from_list(struct list_head *dup_list);
+int populate_active_processes(struct list_head *dup_list);
+
+#endif //__TOOLS_H
+