proto-shell.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. /*
  2. * netifd - network interface daemon
  3. * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2
  7. * as published by the Free Software Foundation
  8. *
  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.
  13. */
  14. #define _GNU_SOURCE
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. #include <glob.h>
  19. #include <unistd.h>
  20. #include <fcntl.h>
  21. #include <signal.h>
  22. #include <arpa/inet.h>
  23. #include <netinet/in.h>
  24. #include <libubox/blobmsg_json.h>
  25. #include "netifd.h"
  26. #include "interface.h"
  27. #include "interface-ip.h"
  28. #include "proto.h"
  29. #include "system.h"
  30. static int proto_fd = -1;
  31. enum proto_shell_sm {
  32. S_IDLE,
  33. S_SETUP,
  34. S_SETUP_ABORT,
  35. S_TEARDOWN,
  36. };
  37. struct proto_shell_handler {
  38. struct list_head list;
  39. struct proto_handler proto;
  40. struct uci_blob_param_list config;
  41. char *config_buf;
  42. bool init_available;
  43. char script_name[];
  44. };
  45. struct proto_shell_dependency {
  46. struct list_head list;
  47. struct proto_shell_state *proto;
  48. struct interface_user dep;
  49. union if_addr host;
  50. bool v6;
  51. char interface[];
  52. };
  53. struct proto_shell_state {
  54. struct interface_proto_state proto;
  55. struct proto_shell_handler *handler;
  56. struct blob_attr *config;
  57. struct uloop_timeout teardown_timeout;
  58. struct netifd_process script_task;
  59. struct netifd_process proto_task;
  60. enum proto_shell_sm sm;
  61. bool proto_task_killed;
  62. int last_error;
  63. struct list_head deps;
  64. };
  65. static void
  66. proto_shell_check_dependencies(struct proto_shell_state *state)
  67. {
  68. struct proto_shell_dependency *dep;
  69. bool available = true;
  70. list_for_each_entry(dep, &state->deps, list) {
  71. if (dep->dep.iface)
  72. continue;
  73. available = false;
  74. break;
  75. }
  76. interface_set_available(state->proto.iface, available);
  77. }
  78. static void
  79. proto_shell_if_up_cb(struct interface_user *dep, struct interface *iface,
  80. enum interface_event ev);
  81. static void
  82. proto_shell_if_down_cb(struct interface_user *dep, struct interface *iface,
  83. enum interface_event ev);
  84. static void
  85. proto_shell_update_host_dep(struct proto_shell_dependency *dep)
  86. {
  87. struct interface *iface = NULL;
  88. if (dep->dep.iface)
  89. goto out;
  90. if (dep->interface[0])
  91. iface = vlist_find(&interfaces, dep->interface, iface, node);
  92. iface = interface_ip_add_target_route(&dep->host, dep->v6, iface);
  93. if (!iface)
  94. goto out;
  95. interface_remove_user(&dep->dep);
  96. dep->dep.cb = proto_shell_if_down_cb;
  97. interface_add_user(&dep->dep, iface);
  98. out:
  99. proto_shell_check_dependencies(dep->proto);
  100. }
  101. static void
  102. proto_shell_clear_host_dep(struct proto_shell_state *state)
  103. {
  104. struct proto_shell_dependency *dep, *tmp;
  105. list_for_each_entry_safe(dep, tmp, &state->deps, list) {
  106. interface_remove_user(&dep->dep);
  107. list_del(&dep->list);
  108. free(dep);
  109. }
  110. }
  111. static int
  112. proto_shell_handler(struct interface_proto_state *proto,
  113. enum interface_proto_cmd cmd, bool force)
  114. {
  115. struct proto_shell_state *state;
  116. struct proto_shell_handler *handler;
  117. struct netifd_process *proc;
  118. static char error_buf[32];
  119. const char *argv[7];
  120. char *envp[2];
  121. const char *action;
  122. char *config;
  123. int ret, i = 0, j = 0;
  124. state = container_of(proto, struct proto_shell_state, proto);
  125. handler = state->handler;
  126. proc = &state->script_task;
  127. if (cmd == PROTO_CMD_SETUP) {
  128. action = "setup";
  129. state->last_error = -1;
  130. proto_shell_clear_host_dep(state);
  131. } else {
  132. if (state->sm == S_TEARDOWN)
  133. return 0;
  134. if (state->script_task.uloop.pending) {
  135. if (state->sm != S_SETUP_ABORT) {
  136. uloop_timeout_set(&state->teardown_timeout, 1000);
  137. kill(state->script_task.uloop.pid, SIGTERM);
  138. if (state->proto_task.uloop.pending)
  139. kill(state->proto_task.uloop.pid, SIGTERM);
  140. state->sm = S_SETUP_ABORT;
  141. }
  142. return 0;
  143. }
  144. action = "teardown";
  145. state->sm = S_TEARDOWN;
  146. if (state->last_error >= 0) {
  147. snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error);
  148. envp[j++] = error_buf;
  149. }
  150. uloop_timeout_set(&state->teardown_timeout, 5000);
  151. }
  152. config = blobmsg_format_json(state->config, true);
  153. if (!config)
  154. return -1;
  155. argv[i++] = handler->script_name;
  156. argv[i++] = handler->proto.name;
  157. argv[i++] = action;
  158. argv[i++] = proto->iface->name;
  159. argv[i++] = config;
  160. if (proto->iface->main_dev.dev)
  161. argv[i++] = proto->iface->main_dev.dev->ifname;
  162. argv[i] = NULL;
  163. envp[j] = NULL;
  164. ret = netifd_start_process(argv, envp, proc);
  165. free(config);
  166. return ret;
  167. }
  168. static void
  169. proto_shell_if_up_cb(struct interface_user *dep, struct interface *iface,
  170. enum interface_event ev)
  171. {
  172. struct proto_shell_dependency *pdep;
  173. if (ev != IFEV_UP)
  174. return;
  175. pdep = container_of(dep, struct proto_shell_dependency, dep);
  176. proto_shell_update_host_dep(pdep);
  177. }
  178. static void
  179. proto_shell_if_down_cb(struct interface_user *dep, struct interface *iface,
  180. enum interface_event ev)
  181. {
  182. struct proto_shell_dependency *pdep;
  183. struct proto_shell_state *state;
  184. if (ev == IFEV_UP)
  185. return;
  186. pdep = container_of(dep, struct proto_shell_dependency, dep);
  187. interface_remove_user(dep);
  188. dep->cb = proto_shell_if_up_cb;
  189. interface_add_user(dep, NULL);
  190. state = pdep->proto;
  191. if (state->sm == S_IDLE) {
  192. state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
  193. proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
  194. }
  195. }
  196. static void
  197. proto_shell_task_finish(struct proto_shell_state *state,
  198. struct netifd_process *task)
  199. {
  200. switch (state->sm) {
  201. case S_IDLE:
  202. if (task == &state->proto_task)
  203. state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
  204. /* fall through */
  205. case S_SETUP:
  206. if (task == &state->proto_task)
  207. proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN,
  208. false);
  209. break;
  210. case S_SETUP_ABORT:
  211. if (state->script_task.uloop.pending ||
  212. state->proto_task.uloop.pending)
  213. break;
  214. uloop_timeout_cancel(&state->teardown_timeout);
  215. state->sm = S_IDLE;
  216. proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
  217. break;
  218. case S_TEARDOWN:
  219. if (state->script_task.uloop.pending)
  220. break;
  221. if (state->proto_task.uloop.pending) {
  222. if (!state->proto_task_killed)
  223. kill(state->proto_task.uloop.pid, SIGTERM);
  224. break;
  225. }
  226. uloop_timeout_cancel(&state->teardown_timeout);
  227. state->sm = S_IDLE;
  228. state->proto.proto_event(&state->proto, IFPEV_DOWN);
  229. break;
  230. }
  231. }
  232. static void
  233. proto_shell_teardown_timeout_cb(struct uloop_timeout *timeout)
  234. {
  235. struct proto_shell_state *state;
  236. state = container_of(timeout, struct proto_shell_state, teardown_timeout);
  237. netifd_kill_process(&state->script_task);
  238. netifd_kill_process(&state->proto_task);
  239. proto_shell_task_finish(state, NULL);
  240. }
  241. static void
  242. proto_shell_script_cb(struct netifd_process *p, int ret)
  243. {
  244. struct proto_shell_state *state;
  245. state = container_of(p, struct proto_shell_state, script_task);
  246. proto_shell_task_finish(state, p);
  247. }
  248. static void
  249. proto_shell_task_cb(struct netifd_process *p, int ret)
  250. {
  251. struct proto_shell_state *state;
  252. state = container_of(p, struct proto_shell_state, proto_task);
  253. if (state->sm == S_IDLE || state->sm == S_SETUP)
  254. state->last_error = WEXITSTATUS(ret);
  255. proto_shell_task_finish(state, p);
  256. }
  257. static void
  258. proto_shell_free(struct interface_proto_state *proto)
  259. {
  260. struct proto_shell_state *state;
  261. state = container_of(proto, struct proto_shell_state, proto);
  262. uloop_timeout_cancel(&state->teardown_timeout);
  263. proto_shell_clear_host_dep(state);
  264. netifd_kill_process(&state->script_task);
  265. netifd_kill_process(&state->proto_task);
  266. free(state->config);
  267. free(state);
  268. }
  269. static void
  270. proto_shell_parse_route_list(struct interface *iface, struct blob_attr *attr,
  271. bool v6)
  272. {
  273. struct blob_attr *cur;
  274. int rem;
  275. blobmsg_for_each_attr(cur, attr, rem) {
  276. if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) {
  277. DPRINTF("Ignore wrong route type: %d\n", blobmsg_type(cur));
  278. continue;
  279. }
  280. interface_ip_add_route(iface, cur, v6);
  281. }
  282. }
  283. static void
  284. proto_shell_parse_data(struct interface *iface, struct blob_attr *attr)
  285. {
  286. struct blob_attr *cur;
  287. int rem;
  288. blobmsg_for_each_attr(cur, attr, rem)
  289. interface_add_data(iface, cur);
  290. }
  291. static struct device *
  292. proto_shell_create_tunnel(const char *name, struct blob_attr *attr)
  293. {
  294. struct device *dev;
  295. struct blob_buf b;
  296. memset(&b, 0, sizeof(b));
  297. blob_buf_init(&b, 0);
  298. blob_put(&b, 0, blobmsg_data(attr), blobmsg_data_len(attr));
  299. dev = device_create(name, &tunnel_device_type, blob_data(b.head));
  300. blob_buf_free(&b);
  301. return dev;
  302. }
  303. enum {
  304. NOTIFY_ACTION,
  305. NOTIFY_ERROR,
  306. NOTIFY_COMMAND,
  307. NOTIFY_ENV,
  308. NOTIFY_SIGNAL,
  309. NOTIFY_AVAILABLE,
  310. NOTIFY_LINK_UP,
  311. NOTIFY_IFNAME,
  312. NOTIFY_ADDR_EXT,
  313. NOTIFY_ROUTES,
  314. NOTIFY_ROUTES6,
  315. NOTIFY_TUNNEL,
  316. NOTIFY_DATA,
  317. NOTIFY_KEEP,
  318. NOTIFY_HOST,
  319. NOTIFY_DNS,
  320. NOTIFY_DNS_SEARCH,
  321. __NOTIFY_LAST
  322. };
  323. static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = {
  324. [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 },
  325. [NOTIFY_ERROR] = { .name = "error", .type = BLOBMSG_TYPE_ARRAY },
  326. [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY },
  327. [NOTIFY_ENV] = { .name = "env", .type = BLOBMSG_TYPE_ARRAY },
  328. [NOTIFY_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 },
  329. [NOTIFY_AVAILABLE] = { .name = "available", .type = BLOBMSG_TYPE_BOOL },
  330. [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL },
  331. [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
  332. [NOTIFY_ADDR_EXT] = { .name = "address-external", .type = BLOBMSG_TYPE_BOOL },
  333. [NOTIFY_ROUTES] = { .name = "routes", .type = BLOBMSG_TYPE_ARRAY },
  334. [NOTIFY_ROUTES6] = { .name = "routes6", .type = BLOBMSG_TYPE_ARRAY },
  335. [NOTIFY_TUNNEL] = { .name = "tunnel", .type = BLOBMSG_TYPE_TABLE },
  336. [NOTIFY_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
  337. [NOTIFY_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL },
  338. [NOTIFY_HOST] = { .name = "host", .type = BLOBMSG_TYPE_STRING },
  339. [NOTIFY_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
  340. [NOTIFY_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY },
  341. };
  342. static int
  343. proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, struct blob_attr **tb)
  344. {
  345. struct interface *iface = state->proto.iface;
  346. struct blob_attr *cur;
  347. struct device *dev;
  348. const char *devname;
  349. int dev_create = 1;
  350. bool addr_ext = false;
  351. bool keep = false;
  352. bool up;
  353. if (!tb[NOTIFY_LINK_UP])
  354. return UBUS_STATUS_INVALID_ARGUMENT;
  355. up = blobmsg_get_bool(tb[NOTIFY_LINK_UP]);
  356. if (!up) {
  357. state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
  358. return 0;
  359. }
  360. if ((cur = tb[NOTIFY_KEEP]) != NULL)
  361. keep = blobmsg_get_bool(cur);
  362. if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) {
  363. addr_ext = blobmsg_get_bool(cur);
  364. if (addr_ext)
  365. dev_create = 2;
  366. }
  367. if (!tb[NOTIFY_IFNAME]) {
  368. if (!iface->main_dev.dev)
  369. return UBUS_STATUS_INVALID_ARGUMENT;
  370. } else if (!keep || iface->state != IFS_UP) {
  371. keep = false;
  372. devname = blobmsg_data(tb[NOTIFY_IFNAME]);
  373. if (tb[NOTIFY_TUNNEL]) {
  374. dev = proto_shell_create_tunnel(devname,
  375. tb[NOTIFY_TUNNEL]);
  376. if (!dev)
  377. return UBUS_STATUS_INVALID_ARGUMENT;
  378. } else {
  379. dev = device_get(devname, dev_create);
  380. if (!dev)
  381. return UBUS_STATUS_NOT_FOUND;
  382. }
  383. interface_set_l3_dev(iface, dev);
  384. device_claim(&iface->l3_dev);
  385. device_set_present(dev, true);
  386. }
  387. if (!keep)
  388. interface_update_start(iface);
  389. proto_apply_ip_settings(iface, data, addr_ext);
  390. if ((cur = tb[NOTIFY_ROUTES]) != NULL)
  391. proto_shell_parse_route_list(state->proto.iface, cur, false);
  392. if ((cur = tb[NOTIFY_ROUTES6]) != NULL)
  393. proto_shell_parse_route_list(state->proto.iface, cur, true);
  394. if ((cur = tb[NOTIFY_DNS]))
  395. interface_add_dns_server_list(&iface->proto_ip, cur);
  396. if ((cur = tb[NOTIFY_DNS_SEARCH]))
  397. interface_add_dns_search_list(&iface->proto_ip, cur);
  398. interface_update_complete(state->proto.iface);
  399. if (!keep)
  400. state->proto.proto_event(&state->proto, IFPEV_UP);
  401. state->sm = S_IDLE;
  402. if ((cur = tb[NOTIFY_DATA]))
  403. proto_shell_parse_data(state->proto.iface, cur);
  404. return 0;
  405. }
  406. static bool
  407. fill_string_list(struct blob_attr *attr, char **argv, int max)
  408. {
  409. struct blob_attr *cur;
  410. int argc = 0;
  411. int rem;
  412. if (!attr)
  413. goto out;
  414. blobmsg_for_each_attr(cur, attr, rem) {
  415. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
  416. return false;
  417. if (!blobmsg_check_attr(cur, NULL))
  418. return false;
  419. argv[argc++] = blobmsg_data(cur);
  420. if (argc == max - 1)
  421. return false;
  422. }
  423. out:
  424. argv[argc] = NULL;
  425. return true;
  426. }
  427. static int
  428. proto_shell_run_command(struct proto_shell_state *state, struct blob_attr **tb)
  429. {
  430. static char *argv[64];
  431. static char *env[32];
  432. if (!tb[NOTIFY_COMMAND])
  433. goto error;
  434. if (!fill_string_list(tb[NOTIFY_COMMAND], argv, ARRAY_SIZE(argv)))
  435. goto error;
  436. if (!fill_string_list(tb[NOTIFY_ENV], env, ARRAY_SIZE(env)))
  437. goto error;
  438. netifd_start_process((const char **) argv, (char **) env, &state->proto_task);
  439. return 0;
  440. error:
  441. return UBUS_STATUS_INVALID_ARGUMENT;
  442. }
  443. static int
  444. proto_shell_kill_command(struct proto_shell_state *state, struct blob_attr **tb)
  445. {
  446. unsigned int signal = ~0;
  447. if (tb[NOTIFY_SIGNAL])
  448. signal = blobmsg_get_u32(tb[NOTIFY_SIGNAL]);
  449. if (signal > 31)
  450. signal = SIGTERM;
  451. if (state->proto_task.uloop.pending) {
  452. state->proto_task_killed = true;
  453. kill(state->proto_task.uloop.pid, signal);
  454. }
  455. return 0;
  456. }
  457. static int
  458. proto_shell_notify_error(struct proto_shell_state *state, struct blob_attr **tb)
  459. {
  460. struct blob_attr *cur;
  461. char *data[16];
  462. int n_data = 0;
  463. int rem;
  464. if (!tb[NOTIFY_ERROR])
  465. return UBUS_STATUS_INVALID_ARGUMENT;
  466. blobmsg_for_each_attr(cur, tb[NOTIFY_ERROR], rem) {
  467. if (n_data + 1 == ARRAY_SIZE(data))
  468. goto error;
  469. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
  470. goto error;
  471. if (!blobmsg_check_attr(cur, NULL))
  472. goto error;
  473. data[n_data++] = blobmsg_data(cur);
  474. }
  475. if (!n_data)
  476. goto error;
  477. interface_add_error(state->proto.iface, state->handler->proto.name,
  478. data[0], (const char **) &data[1], n_data - 1);
  479. return 0;
  480. error:
  481. return UBUS_STATUS_INVALID_ARGUMENT;
  482. }
  483. static int
  484. proto_shell_block_restart(struct proto_shell_state *state, struct blob_attr **tb)
  485. {
  486. state->proto.iface->autostart = false;
  487. return 0;
  488. }
  489. static int
  490. proto_shell_set_available(struct proto_shell_state *state, struct blob_attr **tb)
  491. {
  492. if (!tb[NOTIFY_AVAILABLE])
  493. return UBUS_STATUS_INVALID_ARGUMENT;
  494. interface_set_available(state->proto.iface, blobmsg_get_bool(tb[NOTIFY_AVAILABLE]));
  495. return 0;
  496. }
  497. static int
  498. proto_shell_add_host_dependency(struct proto_shell_state *state, struct blob_attr **tb)
  499. {
  500. struct proto_shell_dependency *dep;
  501. struct blob_attr *host = tb[NOTIFY_HOST];
  502. struct blob_attr *ifname = tb[NOTIFY_IFNAME];
  503. size_t ifnamelen = (ifname) ? blobmsg_data_len(ifname) : 1;
  504. if (!host)
  505. return UBUS_STATUS_INVALID_ARGUMENT;
  506. dep = calloc(1, sizeof(*dep) + ifnamelen);
  507. if (inet_pton(AF_INET, blobmsg_data(host), &dep->host) < 1) {
  508. if (inet_pton(AF_INET6, blobmsg_data(host), &dep->host) < 1) {
  509. free(dep);
  510. return UBUS_STATUS_INVALID_ARGUMENT;
  511. } else {
  512. dep->v6 = true;
  513. }
  514. }
  515. dep->proto = state;
  516. if (ifname)
  517. memcpy(dep->interface, blobmsg_data(ifname), ifnamelen);
  518. else
  519. dep->interface[0] = 0;
  520. dep->dep.cb = proto_shell_if_up_cb;
  521. interface_add_user(&dep->dep, NULL);
  522. list_add(&dep->list, &state->deps);
  523. proto_shell_update_host_dep(dep);
  524. if (!dep->dep.iface)
  525. return UBUS_STATUS_NOT_FOUND;
  526. return 0;
  527. }
  528. static int
  529. proto_shell_setup_failed(struct proto_shell_state *state)
  530. {
  531. switch (state->sm) {
  532. case S_IDLE:
  533. state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
  534. /* fall through */
  535. case S_SETUP:
  536. proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
  537. break;
  538. default:
  539. break;
  540. }
  541. return 0;
  542. }
  543. static int
  544. proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr)
  545. {
  546. struct proto_shell_state *state;
  547. struct blob_attr *tb[__NOTIFY_LAST];
  548. state = container_of(proto, struct proto_shell_state, proto);
  549. blobmsg_parse(notify_attr, __NOTIFY_LAST, tb, blob_data(attr), blob_len(attr));
  550. if (!tb[NOTIFY_ACTION])
  551. return UBUS_STATUS_INVALID_ARGUMENT;
  552. switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) {
  553. case 0:
  554. return proto_shell_update_link(state, attr, tb);
  555. case 1:
  556. return proto_shell_run_command(state, tb);
  557. case 2:
  558. return proto_shell_kill_command(state, tb);
  559. case 3:
  560. return proto_shell_notify_error(state, tb);
  561. case 4:
  562. return proto_shell_block_restart(state, tb);
  563. case 5:
  564. return proto_shell_set_available(state, tb);
  565. case 6:
  566. return proto_shell_add_host_dependency(state, tb);
  567. case 7:
  568. return proto_shell_setup_failed(state);
  569. default:
  570. return UBUS_STATUS_INVALID_ARGUMENT;
  571. }
  572. }
  573. static struct interface_proto_state *
  574. proto_shell_attach(const struct proto_handler *h, struct interface *iface,
  575. struct blob_attr *attr)
  576. {
  577. struct proto_shell_state *state;
  578. state = calloc(1, sizeof(*state));
  579. INIT_LIST_HEAD(&state->deps);
  580. state->config = malloc(blob_pad_len(attr));
  581. if (!state->config)
  582. goto error;
  583. memcpy(state->config, attr, blob_pad_len(attr));
  584. state->proto.free = proto_shell_free;
  585. state->proto.notify = proto_shell_notify;
  586. state->proto.cb = proto_shell_handler;
  587. state->teardown_timeout.cb = proto_shell_teardown_timeout_cb;
  588. state->script_task.cb = proto_shell_script_cb;
  589. state->script_task.dir_fd = proto_fd;
  590. state->script_task.log_prefix = iface->name;
  591. state->proto_task.cb = proto_shell_task_cb;
  592. state->proto_task.dir_fd = proto_fd;
  593. state->proto_task.log_prefix = iface->name;
  594. state->handler = container_of(h, struct proto_shell_handler, proto);
  595. return &state->proto;
  596. error:
  597. free(state);
  598. return NULL;
  599. }
  600. static json_object *
  601. check_type(json_object *obj, json_type type)
  602. {
  603. if (!obj)
  604. return NULL;
  605. if (json_object_get_type(obj) != type)
  606. return NULL;
  607. return obj;
  608. }
  609. static inline json_object *
  610. get_field(json_object *obj, const char *name, json_type type)
  611. {
  612. return check_type(json_object_object_get(obj, name), type);
  613. }
  614. static char *
  615. proto_shell_parse_config(struct uci_blob_param_list *config, json_object *obj)
  616. {
  617. struct blobmsg_policy *attrs;
  618. char *str_buf, *str_cur;
  619. int str_len = 0;
  620. int i;
  621. config->n_params = json_object_array_length(obj);
  622. attrs = calloc(1, sizeof(*attrs) * config->n_params);
  623. if (!attrs)
  624. return NULL;
  625. config->params = attrs;
  626. for (i = 0; i < config->n_params; i++) {
  627. json_object *cur, *name, *type;
  628. cur = check_type(json_object_array_get_idx(obj, i), json_type_array);
  629. if (!cur)
  630. goto error;
  631. name = check_type(json_object_array_get_idx(cur, 0), json_type_string);
  632. if (!name)
  633. goto error;
  634. type = check_type(json_object_array_get_idx(cur, 1), json_type_int);
  635. if (!type)
  636. goto error;
  637. attrs[i].name = json_object_get_string(name);
  638. attrs[i].type = json_object_get_int(type);
  639. if (attrs[i].type > BLOBMSG_TYPE_LAST)
  640. goto error;
  641. str_len += strlen(attrs[i].name) + 1;
  642. }
  643. str_buf = malloc(str_len);
  644. if (!str_buf)
  645. goto error;
  646. str_cur = str_buf;
  647. for (i = 0; i < config->n_params; i++) {
  648. const char *name = attrs[i].name;
  649. attrs[i].name = str_cur;
  650. str_cur += sprintf(str_cur, "%s", name) + 1;
  651. }
  652. return str_buf;
  653. error:
  654. free(attrs);
  655. config->n_params = 0;
  656. return NULL;
  657. }
  658. static void
  659. proto_shell_add_handler(const char *script, json_object *obj)
  660. {
  661. struct proto_shell_handler *handler;
  662. struct proto_handler *proto;
  663. json_object *config, *tmp;
  664. const char *name;
  665. char *str;
  666. if (!check_type(obj, json_type_object))
  667. return;
  668. tmp = get_field(obj, "name", json_type_string);
  669. if (!tmp)
  670. return;
  671. name = json_object_get_string(tmp);
  672. handler = calloc_a(sizeof(*handler) + strlen(script) + 1,
  673. &str, strlen(name) + 1);
  674. if (!handler)
  675. return;
  676. strcpy(handler->script_name, script);
  677. strcpy(str, name);
  678. proto = &handler->proto;
  679. proto->name = str;
  680. proto->config_params = &handler->config;
  681. proto->attach = proto_shell_attach;
  682. tmp = get_field(obj, "no-device", json_type_boolean);
  683. if (tmp && json_object_get_boolean(tmp))
  684. handler->proto.flags |= PROTO_FLAG_NODEV;
  685. tmp = get_field(obj, "available", json_type_boolean);
  686. if (tmp && json_object_get_boolean(tmp))
  687. handler->proto.flags |= PROTO_FLAG_INIT_AVAILABLE;
  688. config = get_field(obj, "config", json_type_array);
  689. if (config)
  690. handler->config_buf = proto_shell_parse_config(&handler->config, config);
  691. DPRINTF("Add handler for script %s: %s\n", script, proto->name);
  692. add_proto_handler(proto);
  693. }
  694. static void proto_shell_add_script(const char *name)
  695. {
  696. struct json_tokener *tok = NULL;
  697. json_object *obj;
  698. static char buf[512];
  699. char *start, *cmd;
  700. FILE *f;
  701. int len;
  702. #define DUMP_SUFFIX " '' dump"
  703. cmd = alloca(strlen(name) + 1 + sizeof(DUMP_SUFFIX));
  704. sprintf(cmd, "%s" DUMP_SUFFIX, name);
  705. f = popen(cmd, "r");
  706. if (!f)
  707. return;
  708. do {
  709. start = fgets(buf, sizeof(buf), f);
  710. if (!start)
  711. continue;
  712. len = strlen(start);
  713. if (!tok)
  714. tok = json_tokener_new();
  715. obj = json_tokener_parse_ex(tok, start, len);
  716. if (!is_error(obj)) {
  717. proto_shell_add_handler(name, obj);
  718. json_object_put(obj);
  719. json_tokener_free(tok);
  720. tok = NULL;
  721. } else if (start[len - 1] == '\n') {
  722. json_tokener_free(tok);
  723. tok = NULL;
  724. }
  725. } while (!feof(f) && !ferror(f));
  726. if (tok)
  727. json_tokener_free(tok);
  728. pclose(f);
  729. }
  730. static void __init proto_shell_init(void)
  731. {
  732. glob_t g;
  733. int main_fd;
  734. int i;
  735. main_fd = open(".", O_RDONLY | O_DIRECTORY);
  736. if (main_fd < 0)
  737. return;
  738. if (chdir(main_path)) {
  739. perror("chdir(main path)");
  740. goto close_cur;
  741. }
  742. if (chdir("./proto"))
  743. goto close_cur;
  744. proto_fd = open(".", O_RDONLY | O_DIRECTORY);
  745. if (proto_fd < 0)
  746. goto close_cur;
  747. system_fd_set_cloexec(proto_fd);
  748. glob("./*.sh", 0, NULL, &g);
  749. for (i = 0; i < g.gl_pathc; i++)
  750. proto_shell_add_script(g.gl_pathv[i]);
  751. close_cur:
  752. fchdir(main_fd);
  753. close(main_fd);
  754. }