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 +