2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <sys/socket.h>
17 #include <sys/types.h>
19 #include <linux/types.h>
20 #include <linux/netlink.h>
22 #include <libubox/blobmsg_json.h>
23 #include <libubox/json_script.h>
24 #include <libubox/runqueue.h>
25 #include <libubox/ustream.h>
26 #include <libubox/uloop.h>
36 struct list_head list
;
46 struct blob_attr
*rule
;
47 struct blob_attr
*data
;
48 struct uloop_timeout delay
;
50 struct json_script_ctx jctx
;
56 void (*handler
)(struct job
*job
, struct blob_attr
*exec
, struct blob_attr
*env
);
60 struct runqueue_process proc
;
62 struct trigger
*trigger
;
63 struct blob_attr
*exec
;
64 struct blob_attr
*env
;
67 static LIST_HEAD(triggers
);
68 static struct runqueue q
;
70 static const char* rule_handle_var(struct json_script_ctx
*ctx
, const char *name
, struct blob_attr
*vars
)
75 static struct json_script_file
*
76 rule_load_script(struct json_script_ctx
*ctx
, const char *name
)
78 struct trigger
*t
= container_of(ctx
, struct trigger
, jctx
);
80 return json_script_file_from_blobmsg(t
->type
, t
->rule
, blob_pad_len(t
->rule
));
83 static void q_job_run(struct runqueue
*q
, struct runqueue_task
*t
)
85 struct job
*j
= container_of(t
, struct job
, proc
.task
);
87 LOG("handle event %s\n", j
->cmd
->name
);
88 j
->cmd
->handler(j
, j
->exec
, j
->env
);
91 static void q_job_complete(struct runqueue
*q
, struct runqueue_task
*p
)
93 struct job
*j
= container_of(p
, struct job
, proc
.task
);
95 if (j
->trigger
->remove
) {
96 list_del(&j
->trigger
->list
);
99 j
->trigger
->pending
= 0;
104 static void add_job(struct trigger
*t
, struct cmd
*cmd
, struct blob_attr
*exec
, struct blob_attr
*data
)
106 static const struct runqueue_task_type job_type
= {
108 .cancel
= runqueue_process_cancel_cb
,
109 .kill
= runqueue_process_kill_cb
,
111 struct blob_attr
*d
, *e
;
112 struct job
*j
= calloc_a(sizeof(*j
), &e
, blob_pad_len(exec
), &d
, blob_pad_len(data
));
118 j
->proc
.task
.type
= &job_type
;
119 j
->proc
.task
.complete
= q_job_complete
;
122 memcpy(j
->exec
, exec
, blob_pad_len(exec
));
123 memcpy(j
->env
, data
, blob_pad_len(data
));
125 runqueue_task_add(&q
, &j
->proc
.task
, false);
128 static void _setenv(const char *key
, const char *val
)
132 snprintf(_key
, sizeof(_key
), "PARAM_%s", key
);
133 setenv(_key
, val
, 1);
136 static void handle_run_script(struct job
*j
, struct blob_attr
*exec
, struct blob_attr
*env
)
139 struct blob_attr
*cur
;
149 runqueue_process_add(&q
, &j
->proc
, pid
);
155 close(STDOUT_FILENO
);
156 close(STDERR_FILENO
);
159 _setenv("type", j
->trigger
->type
);
160 blobmsg_for_each_attr(cur
, j
->env
, rem
)
161 _setenv(blobmsg_name(cur
), blobmsg_data(cur
));
163 blobmsg_for_each_attr(cur
, j
->exec
, rem
) {
164 argv
[i
] = blobmsg_data(cur
);
172 execvp(argv
[0], &argv
[0]);
178 static struct cmd handlers
[] = {
180 .name
= "run_script",
181 .handler
= handle_run_script
,
185 static void rule_handle_command(struct json_script_ctx
*ctx
, const char *name
,
186 struct blob_attr
*exec
, struct blob_attr
*vars
)
188 struct trigger
*t
= container_of(ctx
, struct trigger
, jctx
);
194 for (i
= 0; i
< ARRAY_SIZE(handlers
); i
++) {
195 if (!strcmp(handlers
[i
].name
, name
)) {
196 add_job(t
, &handlers
[i
], exec
, vars
);
202 static void rule_handle_error(struct json_script_ctx
*ctx
, const char *msg
,
203 struct blob_attr
*context
)
207 s
= blobmsg_format_json(context
, false);
208 ERROR("ERROR: %s in block: %s\n", msg
, s
);
212 static void q_empty(struct runqueue
*q
)
216 static void trigger_delay_cb(struct uloop_timeout
*tout
)
218 struct trigger
*t
= container_of(tout
, struct trigger
, delay
);
220 json_script_run(&t
->jctx
, "foo", t
->data
);
224 static struct trigger
* _trigger_add(char *type
, struct blob_attr
*rule
, int timeout
, void *id
)
227 struct blob_attr
*_r
;
228 struct trigger
*t
= calloc_a(sizeof(*t
), &_t
, strlen(type
) + 1, &_r
, blob_pad_len(rule
));
232 t
->delay
.cb
= trigger_delay_cb
;
233 t
->timeout
= timeout
;
237 t
->jctx
.handle_var
= rule_handle_var
,
238 t
->jctx
.handle_error
= rule_handle_error
,
239 t
->jctx
.handle_command
= rule_handle_command
,
240 t
->jctx
.handle_file
= rule_load_script
,
242 strcpy(t
->type
, type
);
243 memcpy(t
->rule
, rule
, blob_pad_len(rule
));
245 list_add(&t
->list
, &triggers
);
246 json_script_init(&t
->jctx
);
251 void trigger_add(struct blob_attr
*rule
, void *id
)
253 struct blob_attr
*cur
;
256 blobmsg_for_each_attr(cur
, rule
, rem
) {
257 struct blob_attr
*_cur
, *type
= NULL
, *script
= NULL
, *timeout
= NULL
;
261 if (blobmsg_type(cur
) != BLOBMSG_TYPE_ARRAY
)
264 blobmsg_for_each_attr(_cur
, cur
, _rem
) {
267 if (blobmsg_type(_cur
) == BLOBMSG_TYPE_STRING
)
272 if (blobmsg_type(_cur
) == BLOBMSG_TYPE_ARRAY
)
277 if (blobmsg_type(_cur
) == BLOBMSG_TYPE_INT32
)
283 if (type
&& script
) {
287 t
= blobmsg_get_u32(timeout
);
288 _trigger_add(blobmsg_get_string(type
), script
, t
, id
);
293 void trigger_del(void *id
)
295 struct trigger
*t
, *n
;
297 list_for_each_entry_safe(t
, n
, &triggers
, list
) {
310 void trigger_init(void)
313 q
.empty_cb
= q_empty
;
314 q
.max_running_tasks
= 1;
317 void trigger_event(char *type
, struct blob_attr
*data
)
321 list_for_each_entry(t
, &triggers
, list
) {
322 if (t
->pending
|| t
->remove
)
324 if (!strcmp(t
->type
, type
)) {
326 t
->data
= malloc(blob_pad_len(data
));
327 memcpy(t
->data
, data
, blob_pad_len(data
));
328 uloop_timeout_set(&t
->delay
, t
->timeout
);
330 json_script_run(&t
->jctx
, "foo", data
);