bool teardown_wait_task;
struct netifd_process proto_task;
+ int last_error;
};
static int
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;
if (cmd == PROTO_CMD_SETUP) {
action = "setup";
proc = &state->setup_task;
+ state->last_error = -1;
} else {
action = "teardown";
proc = &state->teardown_task;
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);
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;
return;
}
+ state->last_error = WEXITSTATUS(ret);
state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
}
enum {
NOTIFY_ACTION,
+ NOTIFY_ERROR,
NOTIFY_COMMAND,
NOTIFY_ENV,
NOTIFY_SIGNAL,
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 },
{
struct interface_ip_settings *ip;
struct blob_attr *cur;
+ int dev_create = 1;
bool addr_ext = false;
bool up;
return 0;
}
+ if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) {
+ addr_ext = blobmsg_get_bool(cur);
+ if (addr_ext)
+ dev_create = 2;
+ }
+
if (!tb[NOTIFY_IFNAME]) {
if (!state->proto.iface->main_dev.dev)
return UBUS_STATUS_INVALID_ARGUMENT;
device_remove_user(&state->l3_dev);
device_add_user(&state->l3_dev,
- device_get(blobmsg_data(tb[NOTIFY_IFNAME]), true));
+ device_get(blobmsg_data(tb[NOTIFY_IFNAME]), dev_create));
state->proto.iface->l3_dev = &state->l3_dev;
device_claim(&state->l3_dev);
}
ip = &state->proto.iface->proto_ip;
interface_update_start(state->proto.iface);
- if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL)
- addr_ext = blobmsg_get_bool(cur);
-
if ((cur = tb[NOTIFY_IPADDR]) != NULL)
proto_shell_parse_addr_list(ip, cur, false, addr_ext);
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;
}
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_notify(struct interface_proto_state *proto, struct blob_attr *attr)
{
struct proto_shell_state *state;
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);
default:
return UBUS_STATUS_INVALID_ARGUMENT;
}
}
-struct interface_proto_state *
+static struct interface_proto_state *
proto_shell_attach(const struct proto_handler *h, struct interface *iface,
struct blob_attr *attr)
{
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"
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)
pclose(f);
}
-void __init proto_shell_init(void)
+static void __init proto_shell_init(void)
{
glob_t g;
int main_fd;