From d3da32eca6e50b6be6e846a7f82c8e93c74c45a4 Mon Sep 17 00:00:00 2001
From: Amin Ben Ramdhane <amin.benramdhane@pivasoftware.com>
Date: Mon, 9 Dec 2019 11:24:50 +0100
Subject: [PATCH] opkgd: initial release
the methods that will be generated :
'softwaremanagement' @14751784
"environment":{}
"install":{"path":"String","environment":"String"}
"remove":{"name":"String","environment":"String"}
"du_install":{"url":"String","uuid":"String","username":"String","password":"String","environment":"String"}
"du_update":{"uuid":"String","url":"String","version":"String","username":"String","password":"String"}
"du_uninstall":{"name":"String","environment":"String"}
"du_list":{"index":"Integer"}
"eu_list":{}
---
Makefile | 17 +
common.c | 501 ++++++++++++++++++++++
common.h | 94 +++++
opkg.c | 1210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 1822 insertions(+)
create mode 100644 Makefile
create mode 100644 common.c
create mode 100644 common.h
create mode 100644 opkg.c
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..783e880
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+PROG = opkgd
+OBJS =opkg.o common.o
+
+PROG_CFLAGS = $(CFLAGS) -fstrict-aliasing -Wall -Wextra
+PROG_LDFLAGS = $(LDFLAGS)
+PROG_LDFLAGS += -luci -lubus -lubox -ljson-c -lblobmsg_json -luuid
+
+%.o: %.c
+ $(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
+
+all: opkgd
+
+opkgd: $(OBJS)
+ $(CC) $(PROG_LDFLAGS) -o $@ $^
+
+clean:
+ rm -f *.o $(PROG)
diff --git a/common.c b/common.c
new file mode 100644
index 0000000..3b56fe6
--- /dev/null
+++ b/common.c
@@ -0,0 +1,501 @@
+/*
+ * common.c: OPKG 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_opkg = NULL;
+
+int opkg_uci_init(void)
+{
+ uci_ctx_opkg = uci_alloc_context();
+ if (!uci_ctx_opkg) {
+ return -1;
+ }
+ uci_add_delta_path(uci_ctx_opkg, uci_ctx_opkg->savedir);
+ uci_set_savedir(uci_ctx_opkg, OPKG_SAVEDIR_PATH);
+ uci_set_confdir(uci_ctx_opkg, OPKG_CONFDIR_PATH);
+ return 0;
+}
+
+int opkg_uci_fini(void)
+{
+ if (uci_ctx_opkg) {
+ uci_free_context(uci_ctx_opkg);
+ }
+ return 0;
+}
+
+static bool opkg_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 opkg_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 && !opkg_uci_validate_section(ptr->section))
+ ptr->flags |= UCI_LOOKUP_EXTENDED;
+
+ return 0;
+
+error:
+ return -1;
+}
+
+struct uci_section *opkg_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 (opkg_uci_init_ptr(&ptr, package, NULL, NULL, NULL)) {
+ return NULL;
+ }
+ if (uci_lookup_ptr(uci_ctx_opkg, &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 (opkg_uci_init_ptr(&ptr, package, NULL, NULL, NULL)) {
+ return NULL;
+ }
+ if (uci_lookup_ptr(uci_ctx_opkg, &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 opkg_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 *opkg_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 opkg_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 = opkg_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 *opkg_uci_get_value_by_section(struct uci_section *section, char *option)
+{
+ struct uci_ptr ptr;
+ char *val = "";
+
+ if (opkg_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) {
+ opkg_uci_print_list(&ptr.o->v.list, &val, " ");
+ return val;
+ }
+
+ if (ptr.o->v.string)
+ return ptr.o->v.string;
+ else
+ return val;
+}
+
+char *opkg_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 (opkg_uci_lookup_ptr_by_section(&ptr, section, option, value) != UCI_OK)
+ return "";
+
+ uci_set(uci_ctx_opkg, &ptr);
+
+ if (ret == UCI_OK)
+ ret = uci_save(uci_ctx_opkg, ptr.p);
+
+ if (ptr.o && ptr.o->v.string)
+ return ptr.o->v.string;
+
+ return "";
+}
+
+struct uci_section *opkg_uci_add_section(char *package, char *section_type)
+{
+ struct uci_ptr ptr;
+ struct uci_section *s = NULL;
+
+ if (opkg_uci_init_ptr(&ptr, package, NULL, NULL, NULL))
+ return NULL;
+
+ if (uci_lookup_ptr(uci_ctx_opkg, &ptr, NULL, true) != UCI_OK)
+ return NULL;
+
+ int ret = uci_add_section(uci_ctx_opkg, ptr.p, section_type, &s);
+ if (ret != UCI_OK)
+ return NULL;
+
+ return s;
+}
+
+int opkg_uci_delete_by_section(struct uci_section *section, char *option, char *value)
+{
+ struct uci_ptr ptr = {0};
+
+ if (section == NULL)
+ return -1;
+
+ if (opkg_uci_lookup_ptr_by_section(&ptr, section, option, value) != UCI_OK)
+ return -1;
+
+ if (uci_delete(uci_ctx_opkg, &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] = "";
+ 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], state[16];
+ 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] = "";
+
+ 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[64] = "", euid_num[8] = "";
+ int i;
+
+ srand(time(NULL));
+ if (sysnchronise) {
+ for (i = 0; i < 59; i++)
+ euid[i] = buf[rand() % 35];
+ euid[59] = '\0';
+ sprintf(euid_num, "%04d", number);
+ strcat(euid, euid_num);
+ } else {
+ for (i = 0; i < 62; i++)
+ euid[i] = buf[rand() % 35];
+ euid[63] = '\0';
+ }
+ return strdup(euid);
+}
+
+int synchronize_deployment_units_with_map_du_file(void)
+{
+ struct uci_section *s = NULL, *stmp = NULL;
+ char path[256], line[256], name[64], version[64], command[256];
+ FILE *log;
+ DIR *dir;
+ struct dirent *ent;
+ int found, incr = 0;
+
+ opkg_uci_foreach_section_safe("map_du", "deployment", stmp, s) {
+ char *map_du_name = opkg_uci_get_value_by_section(s, "name");
+ char *map_du_env = opkg_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))
+ opkg_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)) {
+ opkg_uci_foreach_section("map_du", "deployment", s) {
+ char *map_name = opkg_uci_get_value_by_section(s, "name");
+ char *map_env = opkg_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 = opkg_uci_add_section("map_du", "deployment");
+ char *uuid = generate_uuid();
+ char *duid = generate_duid(true, incr);
+ incr++;
+ opkg_uci_set_value_by_section(new_s, "name", name);
+ opkg_uci_set_value_by_section(new_s, "version", version);
+ opkg_uci_set_value_by_section(new_s, "uuid", uuid);
+ opkg_uci_set_value_by_section(new_s, "duid", duid);
+ opkg_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)) {
+ opkg_uci_foreach_section("map_du", "deployment", s) {
+ char *map_name = opkg_uci_get_value_by_section(s, "name");
+ char *map_env = opkg_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 = opkg_uci_add_section("map_du", "deployment");
+ char *uuid = generate_uuid();
+ char *duid = generate_duid(true, incr);
+ incr++;
+ opkg_uci_set_value_by_section(new_s, "name", name);
+ opkg_uci_set_value_by_section(new_s, "version", version);
+ opkg_uci_set_value_by_section(new_s, "uuid", uuid);
+ opkg_uci_set_value_by_section(new_s, "duid", duid);
+ opkg_uci_set_value_by_section(new_s, "environment", ent->d_name);
+ FREE(uuid);
+ FREE(duid);
+ }
+ }
+ pclose(log);
+ }
+ }
+ if (dir) closedir(dir);
+ }
+ return 0;
+}
+
+void opkg_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 opkg_delete_data_from_list(struct process_res *proc)
+{
+ list_del(&proc->list);
+ FREE(proc->cmd);
+ FREE(proc);
+}
+
+void opkg_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);
+ opkg_delete_data_from_list(proc);
+ }
+}
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..9a5b496
--- /dev/null
+++ b/common.h
@@ -0,0 +1,94 @@
+/*
+ * common.h: OPKG 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
+ */
+
+#ifndef __COMMON_H
+#define __COMMON_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 OPKG_SAVEDIR_PATH "/etc/opkg"
+#define OPKG_CONFDIR_PATH "/etc/opkg"
+#define OPKG_INFO_PATH "/usr/lib/opkg/info"
+#define DEPLOYMENT_UNIT_PATH "/etc/opkg/map_du"
+#define PROC_PATH "/proc"
+#define LXC_PATH "/srv/lxc"
+#define LXC_INFO "/usr/bin/lxc-info"
+
+#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
+
+struct process_res
+{
+ struct list_head list;
+ char *cmd;
+ int pid;
+ unsigned int vsize;
+};
+
+int opkg_uci_init(void);
+int opkg_uci_fini(void);
+struct uci_section *opkg_uci_walk_section(char *package, char *section_type, struct uci_section *prev_section);
+struct uci_section *opkg_uci_add_section(char *package, char *section_type);
+int opkg_uci_delete_by_section(struct uci_section *section, char *option, char *value);
+char *opkg_uci_get_value_by_section(struct uci_section *section, char *option);
+char *opkg_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 opkg_add_data_to_list(struct list_head *dup_list, char *cmd, int pid, unsigned int vsize);
+void opkg_free_data_from_list(struct list_head *dup_list);
+
+#define opkg_uci_foreach_section(package, section_type, section) \
+ for (section = opkg_uci_walk_section(package, section_type, NULL); \
+ section != NULL; \
+ section = opkg_uci_walk_section(package, section_type, section))
+
+#define opkg_uci_foreach_section_safe(package, section_type, _tmp, section) \
+ for(section = opkg_uci_walk_section(package, section_type, NULL), \
+ _tmp = (section) ? opkg_uci_walk_section(package, section_type, section) : NULL; \
+ section != NULL; \
+ section = _tmp, _tmp = (section) ? opkg_uci_walk_section(package, section_type, section) : NULL)
+
+#endif //__COMMON_H
+
diff --git a/opkg.c b/opkg.c
new file mode 100644
index 0000000..33641c1
--- /dev/null
+++ b/opkg.c
@@ -0,0 +1,1210 @@
+/*
+ * main.c: OPKG 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 <stdio.h>
+#include <unistd.h>
+#include <libubox/blobmsg.h>
+#include <libubox/uloop.h>
+#include <libubus.h>
+
+#include "common.h"
+
+static int opkg_software_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], vendor[64], version[64], command[256];
+ char allocateddiskspace[10], availablediskspace[10], allocated_memory[10], available_memory[10];
+ struct blob_buf bb;
+
+ memset(&bb,0,sizeof(struct blob_buf));
+ blob_buf_init(&bb, 0);
+
+ a = blobmsg_open_array(&bb, "environment");
+
+ t = blobmsg_open_table(&bb, "");
+ blobmsg_add_string(&bb, "name", "OpenWRT_Linux");
+ blobmsg_add_string(&bb, "status", "Up");
+ blobmsg_add_string(&bb, "type", "Linux");
+
+ if ((in = popen("uname -o", "r"))) {
+ fgets(buf, sizeof(buf), in);
+ pclose(in);
+ remove_newline(buf);
+ strncpy(vendor, buf, sizeof(vendor));
+ }
+ blobmsg_add_string(&bb, "vendor", vendor);
+
+ if ((in = popen("uname -r", "r"))) {
+ fgets(buf, sizeof(buf), in);
+ pclose(in);
+ remove_newline(buf);
+ strncpy(version, buf, sizeof(version));
+ }
+ blobmsg_add_string(&bb, "version", version);
+
+ if ((in = popen("free | grep Mem | awk '{print$2}'", "r"))) {
+ fgets(buf, sizeof(buf), in);
+ pclose(in);
+ remove_newline(buf);
+ strncpy(allocateddiskspace, buf, sizeof(allocateddiskspace));
+ }
+ blobmsg_add_u32(&bb, "allocateddiskspace", atoi(allocateddiskspace));
+
+ if ((in = popen("free | grep Mem | awk '{print$4}'", "r"))) {
+ fgets(buf, sizeof(buf), in);
+ pclose(in);
+ remove_newline(buf);
+ strncpy(availablediskspace, buf, sizeof(availablediskspace));
+ }
+ blobmsg_add_u32(&bb, "availablediskspace", atoi(availablediskspace));
+
+ if ((in = popen("df | grep overlayfs | awk '{print$2}'", "r"))) {
+ fgets(buf, sizeof(buf), in);
+ pclose(in);
+ remove_newline(buf);
+ strncpy(allocated_memory, buf, sizeof(allocated_memory));
+ }
+ blobmsg_add_u32(&bb, "allocatedmemory", atoi(allocated_memory));
+
+ if ((in = popen("df | grep overlayfs | awk '{print$4}'", "r"))) {
+ fgets(buf, sizeof(buf), in);
+ pclose(in);
+ remove_newline(buf);
+ strncpy(available_memory, buf, sizeof(available_memory));
+ }
+ blobmsg_add_u32(&bb, "availablememory", atoi(available_memory));
+ blobmsg_close_table(&bb, t);
+
+ 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);
+ strncpy(vendor, buf, sizeof(vendor));
+ }
+ blobmsg_add_string(&bb, "vendor", vendor);
+ }
+
+ 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);
+ strncpy(version, buf, sizeof(version));
+ }
+ blobmsg_add_string(&bb, "version", version);
+ }
+
+ if (islxcrunning(ent->d_name))
+ blobmsg_add_u32(&bb, "allocateddiskspace", 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);
+ strncpy(allocateddiskspace, buf, sizeof(allocateddiskspace));
+ }
+ blobmsg_add_u32(&bb, "allocateddiskspace", atoi(allocateddiskspace));
+ }
+
+ if (islxcrunning(ent->d_name))
+ blobmsg_add_u32(&bb, "availablediskspace", 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);
+ strncpy(availablediskspace, buf, sizeof(availablediskspace));
+ }
+ blobmsg_add_u32(&bb, "availablediskspace", atoi(availablediskspace));
+ }
+
+ if (islxcrunning(ent->d_name))
+ blobmsg_add_u32(&bb, "allocatedmemory", 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);
+ strncpy(allocated_memory, buf, sizeof(allocated_memory));
+ }
+ blobmsg_add_u32(&bb, "allocatedmemory", atoi(allocated_memory));
+ }
+
+ if (islxcrunning(ent->d_name))
+ blobmsg_add_u32(&bb, "availablememory", 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);
+ strncpy(available_memory, buf, sizeof(available_memory));
+ }
+ blobmsg_add_u32(&bb, "availablememory", atoi(available_memory));
+ }
+
+ blobmsg_close_table(&bb, t);
+ }
+ if (dir) closedir(dir);
+ }
+
+ 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 opkg_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], command[512], package_path[256];
+ 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)))
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ if (tb[INSTALL_PATH]) {
+ strncpy(package_path, blobmsg_get_string(tb[INSTALL_PATH]), sizeof(package_path));
+ if (!isfileexist(package_path))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ } else {
+ 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));
+ 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);
+ }
+
+ 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 opkg_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], command[256];
+ struct dirent *ent;
+ DIR *dir;
+ FILE *log;
+ int found;
+
+ 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));
+ 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);
+ }
+
+ 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 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 },
+};
+
+static int opkg_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], command[512], name[64], version[64];
+ 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)))
+ 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));
+ blob_buf_init(&bb, 0);
+
+ if ((log = popen(command, "r"))) {
+ while(fgets(line, sizeof(line), log) != NULL) {
+ if (strstr(line, "Downloading"))
+ i++;
+
+ if (strstr(line, "Installing") || strstr(line, "installed")) {
+ sscanf(line, "Installing %63s (%63[^)] to root...", name, version);
+ i++;
+ }
+
+ if (strstr(line, "Configuring"))
+ i++;
+ }
+ pclose(log);
+ }
+
+ 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 = opkg_uci_add_section("map_du", "deployment");
+ opkg_uci_set_value_by_section(new_s, "name", name);
+ opkg_uci_set_value_by_section(new_s, "version", version);
+ opkg_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')
+ opkg_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')
+ opkg_uci_set_value_by_section(new_s, "password", blobmsg_get_string(tb[DU_INSTALL_PASSWORD]));
+
+ if (tb[DU_INSTALL_ENV]) {
+ opkg_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 {
+ opkg_uci_set_value_by_section(new_s, "environment", "OpenWRT_Linux");
+ blobmsg_add_string(&bb,"environment", "OpenWRT_Linux");
+ }
+
+ if (tb[DU_INSTALL_UUID] && *(blobmsg_get_string(tb[DU_INSTALL_UUID])) != '\0') {
+ //use the given UUID
+ opkg_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();
+ opkg_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);
+ opkg_uci_set_value_by_section(new_s, "duid", duid);
+ FREE(duid);
+ }
+
+ ubus_send_reply(ctx, req, bb.head);
+ blob_buf_free(&bb);
+ return 0;
+}
+
+enum {
+ DU_UPDATE_UUID,
+ DU_UPDATE_URL,
+ DU_UPDATE_VERSION,
+ DU_UPDATE_USERNAME,
+ DU_UPDATE_PASSWORD,
+ __DU_UPDATE_MAX
+};
+
+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 },
+};
+
+
+static int opkg_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], command[512], name[64], version[64];
+ 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)))
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ if (!tb[DU_UPDATE_URL])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ synchronize_deployment_units_with_map_du_file();
+
+ opkg_uci_foreach_section("map_du", "deployment", s) {
+ map_uuid = opkg_uci_get_value_by_section(s, "uuid");
+ if (strcmp(map_uuid, blobmsg_get_string(tb[DU_UPDATE_UUID])) == 0) {
+ map_env = opkg_uci_get_value_by_section(s, "environment");
+ opkg_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')
+ opkg_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')
+ opkg_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));
+ blob_buf_init(&bb, 0);
+
+ if ((log = popen(command, "r"))) {
+ while(fgets(line, sizeof(line), log) != NULL) {
+ if (strstr(line, "Downloading"))
+ i++;
+
+ if (strstr(line, "Upgrading")) {
+ sscanf(line, "Upgrading %63s on root from %*s to %63s...", name, version);
+ i++;
+ }
+
+ 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);
+
+ //delete "..." from version string
+ char *p = strstr(version, "...");
+ if (p) *p = '\0';
+
+ blobmsg_add_string(&bb,"version", 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
+ opkg_uci_foreach_section("map_du", "deployment", s) {
+ map_uuid = opkg_uci_get_value_by_section(s, "uuid");
+ if (strcmp(map_uuid, blobmsg_get_string(tb[DU_UPDATE_UUID])) == 0) {
+ opkg_uci_set_value_by_section(s, "version", version);
+ break;
+ }
+ }
+ }
+
+ 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 opkg_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], command[512];
+ 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)))
+ 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));
+ 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);
+ }
+
+ ubus_send_reply(ctx, req, bb.head);
+ blob_buf_free(&bb);
+ return 0;
+}
+
+enum {
+ DU_LIST_INDEX,
+ __DU_LIST_MAX
+};
+
+static const struct blobmsg_policy opkg_du_list_policy[__DU_LIST_MAX] = {
+ [DU_LIST_INDEX] = { .name = "index", .type = BLOBMSG_TYPE_INT32 },
+};
+
+static int opkg_du_list(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_LIST_MAX] = {NULL};
+ struct uci_section *ss = NULL;
+ struct blob_buf bb;
+ void *a, *t;
+ char *config = NULL;
+ FILE *fp;
+ int idx = 0, max = 0, incr = 0;
+
+ if(blobmsg_parse(opkg_du_list_policy, __DU_LIST_MAX, tb, blob_data(msg), blob_len(msg)))
+ return UBUS_STATUS_UNKNOWN_ERROR;
+
+ synchronize_deployment_units_with_map_du_file();
+
+ memset(&bb,0,sizeof(struct blob_buf));
+ blob_buf_init(&bb, 0);
+
+ if (tb[DU_LIST_INDEX]) {
+ idx = blobmsg_get_u32(tb[DU_LIST_INDEX]);
+ max = idx + 100;
+ }
+
+ a = blobmsg_open_array(&bb, "deployment_unit");
+
+ opkg_uci_foreach_section("map_du", "deployment", ss) {
+ if ((incr < idx) && (idx != 0)) {
+ incr++;
+ continue;
+ }
+ char line[256], path[512], *spch = NULL;
+ char *soft_name = opkg_uci_get_value_by_section(ss, "name");
+ char *soft_env = opkg_uci_get_value_by_section(ss, "environment");
+ char *soft_uuid = opkg_uci_get_value_by_section(ss, "uuid");
+ char *soft_duid = opkg_uci_get_value_by_section(ss, "duid");
+ char *soft_version = opkg_uci_get_value_by_section(ss, "version");
+ char *soft_url = opkg_uci_get_value_by_section(ss, "url");
+
+ 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) {
+ 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);
+
+ incr++;
+ if (incr == max) break;
+ }
+ blobmsg_close_array(&bb, a);
+
+ ubus_send_reply(ctx, req, bb.head);
+ blob_buf_free(&bb);
+ return 0;
+}
+
+static int opkg_eu_list(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ DIR *dir, *dir_opkg, *dir_lxc;
+ struct dirent *ent, *ent_opkg, *ent_lxc;
+ char fstat[64], fcmd[64], cmdline[256], fopkg[256], line[256], lxc_proc_path[256], lxc_opkg_info[256];
+ char *package_name;
+ int dgt, pid, ppid, found;
+ unsigned int bsize, vsize;
+ struct blob_buf bb;
+ void *a, *t;
+ FILE *fp;
+
+ 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 ) {
+ 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;
+ opkg_add_data_to_list(&proc_list, cmdline, pid, vsize);
+ }
+ if (dir) closedir(dir);
+
+ sysfs_foreach_file(OPKG_INFO_PATH, dir_opkg, ent_opkg) {
+ if (strstr(ent_opkg->d_name, "busybox")
+ || strstr(ent_opkg->d_name, "bcmkernel")
+ || strstr(ent_opkg->d_name, "juci")
+ || strstr(ent_opkg->d_name, "lib")
+ || strstr(ent_opkg->d_name, ".control")
+ || strstr(ent_opkg->d_name, ".postrm")
+ || strstr(ent_opkg->d_name, ".prerm")
+ || strstr(ent_opkg->d_name, ".preinst")
+ || strstr(ent_opkg->d_name, ".postinst"))
+ continue;
+
+ snprintf(fopkg, sizeof(fopkg), "%s/%s", OPKG_INFO_PATH, ent_opkg->d_name);
+ fp = fopen(fopkg, "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_opkg->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_opkg) closedir(dir_opkg);
+
+ //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;
+
+ snprintf(lxc_proc_path, sizeof(lxc_opkg_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;
+ opkg_add_data_to_list(&proc_list, cmdline, pid, vsize);
+ }
+ if (dir) closedir(dir);
+
+ snprintf(lxc_opkg_info, sizeof(lxc_opkg_info), "%s/%s/rootfs%s", LXC_PATH, ent_lxc->d_name, OPKG_INFO_PATH);
+ sysfs_foreach_file(lxc_opkg_info, dir_opkg, ent_opkg) {
+ if (strstr(ent_opkg->d_name, "busybox")
+ || strstr(ent_opkg->d_name, "bcmkernel")
+ || strstr(ent_opkg->d_name, "juci")
+ || strstr(ent_opkg->d_name, "lib")
+ || strstr(ent_opkg->d_name, ".control")
+ || strstr(ent_opkg->d_name, ".postrm")
+ || strstr(ent_opkg->d_name, ".prerm")
+ || strstr(ent_opkg->d_name, ".preinst")
+ || strstr(ent_opkg->d_name, ".postinst"))
+ continue;
+
+ snprintf(fopkg, sizeof(fopkg), "%s/%s/rootfs%s/%s", LXC_PATH, ent_lxc->d_name, OPKG_INFO_PATH, ent_opkg->d_name);
+ fp = fopen(fopkg, "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_opkg->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_opkg) closedir(dir_opkg);
+ }
+ if (dir_lxc) closedir(dir_lxc);
+ }
+
+ blobmsg_close_array(&bb, a);
+
+ ubus_send_reply(ctx, req, bb.head);
+ blob_buf_free(&bb);
+ opkg_free_data_from_list(&proc_list);
+ return 0;
+}
+
+static struct ubus_method opkg_object_methods[] = {
+ UBUS_METHOD_NOARG("environment", opkg_software_environment),
+ UBUS_METHOD("install", opkg_install, install_policy),
+ UBUS_METHOD("remove", opkg_remove, remove_policy),
+ UBUS_METHOD("du_install", opkg_du_install, du_install_policy),
+ UBUS_METHOD("du_update", opkg_du_update, du_update_policy),
+ UBUS_METHOD("du_uninstall", opkg_du_uninstall, du_uninstall_policy),
+ UBUS_METHOD("du_list", opkg_du_list, opkg_du_list_policy),
+ UBUS_METHOD_NOARG("eu_list", opkg_eu_list),
+};
+
+static struct ubus_object_type opkg_object_type = UBUS_OBJECT_TYPE("softwaremanagement", opkg_object_methods);
+
+static struct ubus_object opkg_object = {
+ .name = "softwaremanagement",
+ .type = &opkg_object_type,
+ .methods = opkg_object_methods,
+ .n_methods = ARRAY_SIZE(opkg_object_methods),
+};
+
+static void opkg_init(struct ubus_context *ctx)
+{
+ int ret;
+
+ ret = ubus_add_object(ctx, &opkg_object);
+ if (ret)
+ fprintf(stderr, "Failed to publish '%s' object : %s\n", opkg_object.name, ubus_strerror(ret));
+
+ uloop_run();
+}
+
+int main(void)
+{
+ const char *ubus_socket = NULL;
+ struct ubus_context *ctx = NULL;
+
+ uloop_init();
+ opkg_uci_init();
+ ctx = ubus_connect(ubus_socket);
+ if (!ctx) {
+ fprintf(stderr, "Failed to connect to ubus\n");
+ return -1;
+ }
+
+ synchronize_deployment_units_with_map_du_file();
+ ubus_add_uloop(ctx);
+ opkg_init(ctx);
+
+ uloop_run();
+ ubus_free(ctx);
+ opkg_uci_fini();
+ if (ctx) ubus_free(ctx);
+ uloop_done();
+
+ return 0;
+}
--
GitLab