X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=proto-shell.c;h=51a6dac17f797f0c895200607fa3ebb85402eff5;hp=a22c0e3b57f5a578b86484980365f16347a72e97;hb=1b48b50c9669ecf3fdd3f50d662fbfd18b971014;hpb=fb0e4138070d7c2ce723af5780e763af3a1353d8 diff --git a/proto-shell.c b/proto-shell.c index a22c0e3..51a6dac 100644 --- a/proto-shell.c +++ b/proto-shell.c @@ -25,6 +25,7 @@ struct proto_shell_handler { struct proto_handler proto; struct config_param_list config; char *config_buf; + bool init_available; char script_name[]; }; @@ -42,6 +43,7 @@ struct proto_shell_state { bool teardown_wait_task; struct netifd_process proto_task; + int last_error; }; static int @@ -51,10 +53,12 @@ proto_shell_handler(struct interface_proto_state *proto, struct proto_shell_state *state; struct proto_shell_handler *handler; struct netifd_process *proc; - const char *argv[6]; + static char error_buf[32]; + const char *argv[7]; + char *envp[2]; const char *action; char *config; - int ret, i = 0; + int ret, i = 0, j = 0; state = container_of(proto, struct proto_shell_state, proto); handler = state->handler; @@ -62,6 +66,7 @@ proto_shell_handler(struct interface_proto_state *proto, if (cmd == PROTO_CMD_SETUP) { action = "setup"; proc = &state->setup_task; + state->last_error = -1; } else { action = "teardown"; proc = &state->teardown_task; @@ -71,6 +76,10 @@ proto_shell_handler(struct interface_proto_state *proto, state->teardown_pending = true; return 0; } + if (state->last_error >= 0) { + snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error); + envp[j++] = error_buf; + } } config = blobmsg_format_json(state->config, true); @@ -85,8 +94,9 @@ proto_shell_handler(struct interface_proto_state *proto, if (proto->iface->main_dev.dev) argv[i++] = proto->iface->main_dev.dev->ifname; argv[i] = NULL; + envp[j] = NULL; - ret = netifd_start_process(argv, NULL, proc); + ret = netifd_start_process(argv, envp, proc); free(config); return ret; @@ -146,6 +156,7 @@ proto_shell_task_cb(struct netifd_process *p, int ret) return; } + state->last_error = WEXITSTATUS(ret); state->proto.proto_event(&state->proto, IFPEV_LINK_LOST); proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false); } @@ -206,9 +217,11 @@ proto_shell_parse_route_list(struct interface *iface, struct blob_attr *attr, enum { NOTIFY_ACTION, + NOTIFY_ERROR, NOTIFY_COMMAND, NOTIFY_ENV, NOTIFY_SIGNAL, + NOTIFY_AVAILABLE, NOTIFY_LINK_UP, NOTIFY_IFNAME, NOTIFY_ADDR_EXT, @@ -223,9 +236,11 @@ enum { static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = { [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 }, + [NOTIFY_ERROR] = { .name = "error", .type = BLOBMSG_TYPE_ARRAY }, [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_AVAILABLE] = { .name = "available", .type = BLOBMSG_TYPE_BOOL }, [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL }, [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, [NOTIFY_ADDR_EXT] = { .name = "address-external", .type = BLOBMSG_TYPE_BOOL }, @@ -332,8 +347,8 @@ out: static int proto_shell_run_command(struct proto_shell_state *state, struct blob_attr **tb) { - char *argv[64]; - char *env[32]; + static char *argv[64]; + static char *env[32]; if (!tb[NOTIFY_COMMAND]) goto error; @@ -372,6 +387,59 @@ proto_shell_kill_command(struct proto_shell_state *state, struct blob_attr **tb) } static int +proto_shell_notify_error(struct proto_shell_state *state, struct blob_attr **tb) +{ + struct blob_attr *cur; + char *data[16]; + int n_data = 0; + int rem; + + if (!tb[NOTIFY_ERROR]) + return UBUS_STATUS_INVALID_ARGUMENT; + + blobmsg_for_each_attr(cur, tb[NOTIFY_ERROR], rem) { + if (n_data + 1 == ARRAY_SIZE(data)) + goto error; + + if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) + goto error; + + if (!blobmsg_check_attr(cur, NULL)) + goto error; + + data[n_data++] = blobmsg_data(cur); + } + + if (!n_data) + goto error; + + interface_add_error(state->proto.iface, state->handler->proto.name, + data[0], (const char **) &data[1], n_data - 1); + + return 0; + +error: + return UBUS_STATUS_INVALID_ARGUMENT; +} + +static int +proto_shell_block_restart(struct proto_shell_state *state, struct blob_attr **tb) +{ + state->proto.iface->autostart = false; + return 0; +} + +static int +proto_shell_set_available(struct proto_shell_state *state, struct blob_attr **tb) +{ + if (!tb[NOTIFY_AVAILABLE]) + return UBUS_STATUS_INVALID_ARGUMENT; + + interface_set_available(state->proto.iface, blobmsg_get_bool(tb[NOTIFY_AVAILABLE])); + return 0; +} + +static int proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr) { struct proto_shell_state *state; @@ -390,6 +458,12 @@ proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr) return proto_shell_run_command(state, tb); case 2: return proto_shell_kill_command(state, tb); + case 3: + return proto_shell_notify_error(state, tb); + case 4: + return proto_shell_block_restart(state, tb); + case 5: + return proto_shell_set_available(state, tb); default: return UBUS_STATUS_INVALID_ARGUMENT; } @@ -542,6 +616,10 @@ proto_shell_add_handler(const char *script, json_object *obj) if (tmp && json_object_get_boolean(tmp)) handler->proto.flags |= PROTO_FLAG_NODEV; + tmp = get_field(obj, "available", json_type_boolean); + if (tmp && json_object_get_boolean(tmp)) + handler->proto.flags |= PROTO_FLAG_INIT_AVAILABLE; + config = get_field(obj, "config", json_type_array); if (config) handler->config_buf = proto_shell_parse_config(&handler->config, config); @@ -555,9 +633,9 @@ static void proto_shell_add_script(const char *name) struct json_tokener *tok = NULL; json_object *obj; static char buf[512]; - char *start, *end, *cmd; + char *start, *cmd; FILE *f; - int buflen, len; + int len; #define DUMP_SUFFIX " '' dump" @@ -569,33 +647,25 @@ static void proto_shell_add_script(const char *name) return; do { - buflen = fread(buf, 1, sizeof(buf) - 1, f); - if (buflen <= 0) + start = fgets(buf, sizeof(buf), f); + if (!start) continue; - start = buf; - len = buflen; - do { - end = memchr(start, '\n', len); - if (end) - len = end - start; - - if (!tok) - tok = json_tokener_new(); - - obj = json_tokener_parse_ex(tok, start, len); - if (!is_error(obj)) { - proto_shell_add_handler(name, obj); - json_object_put(obj); - json_tokener_free(tok); - tok = NULL; - } - - if (end) { - start = end + 1; - len = buflen - (start - buf); - } - } while (len > 0); + len = strlen(start); + + if (!tok) + tok = json_tokener_new(); + + obj = json_tokener_parse_ex(tok, start, len); + if (!is_error(obj)) { + proto_shell_add_handler(name, obj); + json_object_put(obj); + json_tokener_free(tok); + tok = NULL; + } else if (start[len - 1] == '\n') { + json_tokener_free(tok); + tok = NULL; + } } while (!feof(f) && !ferror(f)); if (tok)