[OpenWrt-Devel] [PATCH V2 procd] hotplug: support for interval commands

Rafał Miłecki zajec5 at gmail.com
Sat May 9 16:02:03 EDT 2015


This allows executing code with a given interval. As every command, it
can be assign to any uevent.

Intervals may be useful for counting elapsed time since some action. It
allows e.g. indicating that button has been pressed for some time. This
is useful to let user know he can already release the button.

Signed-off-by: Rafał Miłecki <zajec5 at gmail.com>
---
V2: Use avl instead of flat list
    Use uloop_process: don't spawn multiple processes, monitor them
---
 plug/hotplug.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 166 insertions(+)

diff --git a/plug/hotplug.c b/plug/hotplug.c
index 1a98e8b..83ddc2b 100644
--- a/plug/hotplug.c
+++ b/plug/hotplug.c
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 #include <linux/netlink.h>
 
+#include <libubox/avl-cmp.h>
 #include <libubox/blobmsg_json.h>
 #include <libubox/json_script.h>
 #include <libubox/uloop.h>
@@ -43,7 +44,20 @@ struct cmd_queue {
 	void (*handler)(struct blob_attr *msg, struct blob_attr *data);
 };
 
+struct cmd_interval {
+	struct avl_node avl;
+
+	bool cancelled;
+	struct timespec start;
+	struct uloop_timeout timeout;
+	struct uloop_process process;
+
+	struct blob_attr *msg;
+	struct blob_attr *data;
+};
+
 static LIST_HEAD(cmd_queue);
+static AVL_TREE(cmd_intervals, avl_strcmp, false, NULL);
 static struct uloop_process queue_proc;
 static struct uloop_timeout last_event;
 static struct blob_buf b;
@@ -157,6 +171,150 @@ static void handle_exec(struct blob_attr *msg, struct blob_attr *data)
 	exit(-1);
 }
 
+static void handle_set_interval_timeout(struct uloop_timeout *timeout)
+{
+	struct cmd_interval *interval = container_of(timeout, struct cmd_interval, timeout);
+	struct blob_attr *cur;
+	char *argv[8];
+	int rem, fd;
+	int msecs = 0;
+	int i = 0;
+
+	blobmsg_for_each_attr(cur, interval->data, rem) {
+		switch (i) {
+		case 0:
+			break;
+		case 1:
+			msecs = strtol(blobmsg_get_string(cur), NULL, 0);
+			break;
+		default:
+			argv[i - 2] = blobmsg_data(cur);
+		}
+		i++;
+		if (i - 2 == 7)
+			break;
+	}
+
+	if (interval->process.pending) {
+		uloop_timeout_set(&interval->timeout, msecs);
+		return;
+	}
+
+	interval->process.pid = fork();
+	if (interval->process.pid < 0) {
+		perror("fork");
+	} else if (interval->process.pid == 0) {
+		struct timespec now;
+		char elapsed[6];
+
+		if (i - 2 <= 0)
+			return;
+
+		clock_gettime(CLOCK_MONOTONIC, &now);
+		snprintf(elapsed, sizeof(elapsed), "%ld", now.tv_sec - interval->start.tv_sec);
+
+		blobmsg_for_each_attr(cur, interval->msg, rem)
+			setenv(blobmsg_name(cur), blobmsg_data(cur), 1);
+		setenv("ACTION", "interval", 1);
+		setenv("ELAPSED", elapsed, 1);
+		unsetenv("SEEN");
+
+		if (debug < 3) {
+			fd = open("/dev/null", O_RDWR);
+			if (fd > -1) {
+				dup2(fd, STDIN_FILENO);
+				dup2(fd, STDOUT_FILENO);
+				dup2(fd, STDERR_FILENO);
+				if (fd > STDERR_FILENO)
+					close(fd);
+			}
+		}
+
+		argv[i - 2] = NULL;
+		execvp(argv[0], &argv[0]);
+		exit(-1);
+	} else {
+		uloop_process_add(&interval->process);
+		uloop_timeout_set(&interval->timeout, msecs);
+	}
+}
+
+static void handle_set_interval_process_cb(struct uloop_process *process, int ret)
+{
+	struct cmd_interval *interval = container_of(process, struct cmd_interval, process);
+
+	if (interval->cancelled)
+		free(interval);
+}
+
+static void handle_set_interval(struct blob_attr *msg, struct blob_attr *data)
+{
+	static struct blobmsg_policy set_interval_policy[2] = {
+		{ .type = BLOBMSG_TYPE_STRING },
+		{ .type = BLOBMSG_TYPE_STRING },
+	};
+	struct blob_attr *tb[2];
+	struct cmd_interval *interval;
+	struct blob_attr *_msg, *_data;
+	char *_key;
+	char *name;
+	int msecs;
+
+	blobmsg_parse_array(set_interval_policy, 2, tb, blobmsg_data(data), blobmsg_data_len(data));
+	if (!tb[0] || !tb[1])
+		return;
+	name = blobmsg_get_string(tb[0]);
+	msecs = strtol(blobmsg_get_string(tb[1]), NULL, 0);
+
+	interval = calloc_a(sizeof(struct cmd_interval),
+		&_key, strlen(name) + 1,
+		&_msg, blob_pad_len(msg),
+		&_data, blob_pad_len(data),
+		NULL);
+	if (!interval)
+		return;
+
+	strcpy(_key, name);
+	interval->avl.key = _key;
+	interval->msg = _msg;
+	interval->data = _data;
+	clock_gettime(CLOCK_MONOTONIC, &interval->start);
+	interval->timeout.cb = handle_set_interval_timeout;
+	interval->process.cb = handle_set_interval_process_cb;
+
+	memcpy(interval->msg, msg, blob_pad_len(msg));
+	memcpy(interval->data, data, blob_pad_len(data));
+
+	avl_insert(&cmd_intervals, &interval->avl);
+
+	uloop_timeout_set(&interval->timeout, msecs);
+}
+
+static void handle_clear_interval(struct blob_attr *msg, struct blob_attr *data)
+{
+	static struct blobmsg_policy clear_interval_policy = {
+		.type = BLOBMSG_TYPE_STRING,
+	};
+	struct blob_attr *tb;
+	struct cmd_interval *interval;
+	char *name;
+
+	blobmsg_parse_array(&clear_interval_policy, 1, &tb, blobmsg_data(data), blobmsg_data_len(data));
+	if (!tb)
+		return;
+	name = blobmsg_get_string(tb);
+
+	interval = avl_find_element(&cmd_intervals, name, interval, avl);
+	if (interval) {
+		uloop_timeout_cancel(&interval->timeout);
+		avl_delete(&cmd_intervals, &interval->avl);
+		if (interval->process.pending)
+			interval->cancelled = true;
+		else
+			free(interval);
+	}
+}
+
 static void handle_firmware(struct blob_attr *msg, struct blob_attr *data)
 {
 	char *dir = blobmsg_get_string(blobmsg_data(data));
@@ -254,6 +412,14 @@ static struct cmd_handler {
 		.name = "exec",
 		.handler = handle_exec,
 	}, {
+		.name = "set-interval",
+		.atomic = 1,
+		.handler = handle_set_interval,
+	}, {
+		.name = "clear-interval",
+		.atomic = 1,
+		.handler = handle_clear_interval,
+	}, {
 		.name = "load-firmware",
 		.handler = handle_firmware,
 	},
-- 
1.8.4.5
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list