--- /dev/null
+cmake_minimum_required(VERSION 2.6)
+
+PROJECT(procd C)
+ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -Wmissing-declarations)
+
+SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+
+IF(APPLE)
+ INCLUDE_DIRECTORIES(/opt/local/include)
+ LINK_DIRECTORIES(/opt/local/lib)
+ENDIF()
+
+SET(SOURCES main.c ubus.c)
+
+SET(LIBS ubox ubus)
+
+IF(DEBUG)
+ ADD_DEFINITIONS(-DDEBUG -g3)
+ENDIF()
+
+ADD_EXECUTABLE(procd ${SOURCES})
+
+TARGET_LINK_LIBRARIES(procd ${LIBS})
+
+INSTALL(TARGETS procd
+ RUNTIME DESTINATION sbin
+)
--- /dev/null
+#include <getopt.h>
+#include "procd.h"
+
+int debug = 0;
+
+static int usage(const char *prog)
+{
+ fprintf(stderr, "Usage: %s [options]\n"
+ "Options:\n"
+ " -s <path>: Path to ubus socket\n"
+ " -d: Enable debug messages\n"
+ "\n", prog);
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "ds:")) != -1) {
+ switch (ch) {
+ case 's':
+ ubus_socket = optarg;
+ break;
+ case 'd':
+ debug++;
+ break;
+ default:
+ return usage(argv[0]);
+ }
+ }
+ uloop_init();
+ procd_connect_ubus();
+ uloop_run();
+
+ return 0;
+}
--- /dev/null
+#ifndef __PROCD_H
+#define __PROCD_H
+
+#include <libubox/uloop.h>
+#include <stdio.h>
+
+#define DPRINTF(fmt, ...) do { \
+ if (debug) \
+ fprintf(stderr, "DEBUG %s(%d): " fmt, __func__, __LINE__, ## __VA_ARGS__); \
+ } while (0)
+
+extern int debug;
+extern char *ubus_socket;
+void procd_connect_ubus(void);
+
+#endif
--- /dev/null
+#include <libubox/avl.h>
+#include <libubox/vlist.h>
+
+struct service {
+ struct avl_node avl;
+ const char *name;
+
+ struct vlist_tree instances;
+};
+
+struct service_instance {
+ struct vlist_node node;
+ const char *name;
+
+ struct blob_attr *config;
+ struct uloop_process proc;
+};
+
+
--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <libubus.h>
+
+#include "procd.h"
+
+char *ubus_socket = NULL;
+static struct ubus_context *ctx;
+static struct uloop_process ubus_proc;
+static bool ubus_connected = false;
+
+static void procd_ubus_connection_lost(struct ubus_context *old_ctx);
+
+static void ubus_proc_cb(struct uloop_process *proc, int ret)
+{
+ /* nothing to do here */
+}
+
+static void procd_restart_ubus(void)
+{
+ char *argv[] = { "ubusd", NULL, ubus_socket, NULL };
+
+ if (ubus_proc.pending) {
+ DPRINTF("Killing existing ubus instance, pid=%d\n", (int) ubus_proc.pid);
+ kill(ubus_proc.pid, SIGKILL);
+ uloop_process_delete(&ubus_proc);
+ }
+
+ if (ubus_socket)
+ argv[1] = "-s";
+
+ ubus_proc.pid = fork();
+ if (!ubus_proc.pid) {
+ execvp(argv[0], argv);
+ exit(-1);
+ }
+
+ if (ubus_proc.pid <= 0) {
+ DPRINTF("Failed to start new ubus instance\n");
+ return;
+ }
+
+ DPRINTF("Launched new ubus instance, pid=%d\n", (int) ubus_proc.pid);
+ uloop_process_add(&ubus_proc);
+}
+
+static void procd_ubus_try_connect(void)
+{
+ if (ctx) {
+ ubus_connected = !ubus_reconnect(ctx, ubus_socket);
+ return;
+ }
+
+ ctx = ubus_connect(ubus_socket);
+ if (!ctx) {
+ DPRINTF("Connection to ubus failed\n");
+ return;
+ }
+
+ ctx->connection_lost = procd_ubus_connection_lost;
+ ubus_connected = true;
+}
+
+static void procd_ubus_connection_lost(struct ubus_context *old_ctx)
+{
+ procd_ubus_try_connect();
+ while (!ubus_connected) {
+ procd_restart_ubus();
+ sleep(1);
+ procd_ubus_try_connect();
+ }
+
+ DPRINTF("Connected to ubus, id=%08x\n", ctx->local_id);
+ ubus_add_uloop(ctx);
+}
+
+void procd_connect_ubus(void)
+{
+ ubus_proc.cb = ubus_proc_cb;
+ procd_ubus_connection_lost(NULL);
+}
+