proto-shell: allow proto handlers to export variables to child processes
authorFelix Fietkau <nbd@openwrt.org>
Thu, 13 Oct 2011 23:19:06 +0000 (01:19 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 13 Oct 2011 23:19:06 +0000 (01:19 +0200)
dummy/netifd-proto.sh
proto-shell.c

index 0f703a2..48b1292 100755 (executable)
@@ -33,6 +33,8 @@ _proto_do_teardown() {
 
 _proto_do_setup() {
        json_load "$data"
 
 _proto_do_setup() {
        json_load "$data"
+       _EXPORT_VAR=0
+       _EXPORT_VARS=
        eval "$1_setup \"$interface\" \"$ifname\""
 }
 
        eval "$1_setup \"$interface\" \"$ifname\""
 }
 
@@ -143,6 +145,13 @@ proto_send_update() {
        _proto_notify "$interface"
 }
 
        _proto_notify "$interface"
 }
 
+proto_export() {
+       local var="VAR${_EXPORT_VAR}"
+       _EXPORT_VAR="$(($_EXPORT_VAR + 1))"
+       export -- "$var=$1"
+       jshn_append _EXPORT_VARS "$var"
+}
+
 proto_run_command() {
        local interface="$1"; shift
 
 proto_run_command() {
        local interface="$1"; shift
 
@@ -153,6 +162,14 @@ proto_run_command() {
                json_add_string "" "$1"
                shift
        done
                json_add_string "" "$1"
                shift
        done
+       json_close_array
+       [ -n "$_EXPORT_VARS" ] && {
+               json_add_array env
+               for var in $_EXPORT_VARS; do
+                       eval "json_add_string \"\" \"\${$var}\""
+               done
+               json_close_array
+       }
        _proto_notify "$interface"
 }
 
        _proto_notify "$interface"
 }
 
index 127a79d..e554d79 100644 (file)
@@ -55,7 +55,7 @@ kill_process(struct uloop_process *proc)
 }
 
 static int
 }
 
 static int
-start_process(const char **argv, struct uloop_process *proc)
+start_process(const char **argv, char **env, struct uloop_process *proc)
 {
        int pid;
 
 {
        int pid;
 
@@ -65,6 +65,12 @@ start_process(const char **argv, struct uloop_process *proc)
                return -1;
 
        if (!pid) {
                return -1;
 
        if (!pid) {
+               if (env) {
+                       while (*env) {
+                               putenv(*env);
+                               env++;
+                       }
+               }
                fchdir(proto_fd);
                execvp(argv[0], (char **) argv);
                exit(127);
                fchdir(proto_fd);
                execvp(argv[0], (char **) argv);
                exit(127);
@@ -121,7 +127,7 @@ proto_shell_handler(struct interface_proto_state *proto,
                argv[i++] = proto->iface->main_dev.dev->ifname;
        argv[i] = NULL;
 
                argv[i++] = proto->iface->main_dev.dev->ifname;
        argv[i] = NULL;
 
-       ret = start_process(argv, proc);
+       ret = start_process(argv, NULL, proc);
        free(config);
 
        return ret;
        free(config);
 
        return ret;
@@ -305,10 +311,10 @@ proto_shell_parse_route_list(struct interface *iface, struct blob_attr *attr,
        }
 }
 
        }
 }
 
-
 enum {
        NOTIFY_ACTION,
        NOTIFY_COMMAND,
 enum {
        NOTIFY_ACTION,
        NOTIFY_COMMAND,
+       NOTIFY_ENV,
        NOTIFY_SIGNAL,
        NOTIFY_LINK_UP,
        NOTIFY_IFNAME,
        NOTIFY_SIGNAL,
        NOTIFY_LINK_UP,
        NOTIFY_IFNAME,
@@ -325,6 +331,7 @@ enum {
 static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = {
        [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 },
        [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY },
 static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = {
        [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 },
        [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY },
+       [NOTIFY_ENV] = { .name = "env", .type = BLOBMSG_TYPE_ARRAY },
        [NOTIFY_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 },
        [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL },
        [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
        [NOTIFY_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 },
        [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL },
        [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
@@ -393,30 +400,49 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr **tb)
        return 0;
 }
 
        return 0;
 }
 
-static int
-proto_shell_run_command(struct proto_shell_state *state, struct blob_attr **tb)
+static bool
+fill_string_list(struct blob_attr *attr, char **argv, int max)
 {
        struct blob_attr *cur;
 {
        struct blob_attr *cur;
-       char *argv[64];
        int argc = 0;
        int rem;
 
        int argc = 0;
        int rem;
 
-       if (!tb[NOTIFY_COMMAND])
-               goto error;
+       if (!attr)
+               goto out;
 
 
-       blobmsg_for_each_attr(cur, tb[NOTIFY_COMMAND], rem) {
+       blobmsg_for_each_attr(cur, attr, rem) {
                if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
                if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
-                       goto error;
+                       return false;
 
                if (!blobmsg_check_attr(cur, NULL))
 
                if (!blobmsg_check_attr(cur, NULL))
-                       goto error;
+                       return false;
 
                argv[argc++] = blobmsg_data(cur);
 
                argv[argc++] = blobmsg_data(cur);
-               if (argc == ARRAY_SIZE(argv) - 1)
-                       goto error;
+               if (argc == max - 1)
+                       return false;
        }
        }
+
+out:
        argv[argc] = NULL;
        argv[argc] = NULL;
-       start_process((const char **) argv, &state->proto_task);
+       return true;
+}
+
+static int
+proto_shell_run_command(struct proto_shell_state *state, struct blob_attr **tb)
+{
+       char *argv[64];
+       char *env[32];
+
+       if (!tb[NOTIFY_COMMAND])
+               goto error;
+
+       if (!fill_string_list(tb[NOTIFY_COMMAND], argv, ARRAY_SIZE(argv)))
+               goto error;
+
+       if (!fill_string_list(tb[NOTIFY_ENV], env, ARRAY_SIZE(env)))
+               goto error;
+
+       start_process((const char **) argv, (char **) env, &state->proto_task);
 
        return 0;
 
 
        return 0;