handler.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * netifd - network interface daemon
  3. * Copyright (C) 2012-2013 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 <glob.h>
  16. #include <fcntl.h>
  17. #include <stdio.h>
  18. #include "netifd.h"
  19. #include "system.h"
  20. #include "handler.h"
  21. static int
  22. netifd_dir_push(int fd)
  23. {
  24. int prev_fd = open(".", O_RDONLY | O_DIRECTORY);
  25. system_fd_set_cloexec(prev_fd);
  26. if (fd >= 0)
  27. if (fchdir(fd)) {}
  28. return prev_fd;
  29. }
  30. static void
  31. netifd_dir_pop(int prev_fd)
  32. {
  33. if (prev_fd < 0)
  34. return;
  35. if (fchdir(prev_fd)) {}
  36. close(prev_fd);
  37. }
  38. int netifd_open_subdir(const char *name)
  39. {
  40. int prev_dir;
  41. int ret = -1;
  42. prev_dir = netifd_dir_push(-1);
  43. if (chdir(main_path)) {
  44. perror("chdir(main path)");
  45. goto out;
  46. }
  47. ret = open(name, O_RDONLY | O_DIRECTORY);
  48. if (ret >= 0)
  49. system_fd_set_cloexec(ret);
  50. out:
  51. netifd_dir_pop(prev_dir);
  52. return ret;
  53. }
  54. static void
  55. netifd_init_script_handler(const char *script, json_object *obj, script_dump_cb cb)
  56. {
  57. json_object *tmp;
  58. const char *name;
  59. if (!json_check_type(obj, json_type_object))
  60. return;
  61. tmp = json_get_field(obj, "name", json_type_string);
  62. if (!tmp)
  63. return;
  64. name = json_object_get_string(tmp);
  65. cb(script, name, obj);
  66. }
  67. static void
  68. netifd_init_extdev_handler(const char *config_file, json_object *obj,
  69. create_extdev_handler_cb cb)
  70. {
  71. json_object *tmp, *cfg, *info, *stats;
  72. const char *name, *ubus_name, *br_prefix = NULL;
  73. bool bridge_support = true;
  74. char *err_missing;
  75. if (!json_check_type(obj, json_type_object))
  76. return;
  77. tmp = json_get_field(obj, "name", json_type_string);
  78. if (!tmp) {
  79. err_missing = "name";
  80. goto field_missing;
  81. }
  82. name = json_object_get_string(tmp);
  83. tmp = json_get_field(obj, "ubus_name", json_type_string);
  84. if (!tmp) {
  85. err_missing = "ubus_name";
  86. goto field_missing;
  87. }
  88. ubus_name = json_object_get_string(tmp);
  89. tmp = json_get_field(obj, "bridge", json_type_string);
  90. if (!tmp || !strcmp(json_object_get_string(tmp), "0"))
  91. bridge_support = false;
  92. if (bridge_support) {
  93. tmp = json_get_field(obj, "br-prefix", json_type_string);
  94. if (!tmp)
  95. br_prefix = name;
  96. else
  97. br_prefix = json_object_get_string(tmp);
  98. }
  99. tmp = json_get_field(obj, "config", json_type_array);
  100. if (!tmp) {
  101. err_missing = "config";
  102. goto field_missing;
  103. }
  104. cfg = tmp;
  105. info = json_get_field(obj, "info", json_type_array);
  106. stats = json_get_field(obj, "stats", json_type_array);
  107. cb(config_file, name, ubus_name, bridge_support, br_prefix, cfg, info, stats);
  108. return;
  109. field_missing:
  110. netifd_log_message(L_WARNING, "external device handler description '%s' is"
  111. "missing field '%s'\n", config_file, err_missing);
  112. }
  113. static void
  114. netifd_parse_script_handler(const char *name, script_dump_cb cb)
  115. {
  116. struct json_tokener *tok = NULL;
  117. json_object *obj;
  118. static char buf[512];
  119. char *start, *cmd;
  120. FILE *f;
  121. int len;
  122. #define DUMP_SUFFIX " '' dump"
  123. cmd = alloca(strlen(name) + 1 + sizeof(DUMP_SUFFIX));
  124. sprintf(cmd, "%s" DUMP_SUFFIX, name);
  125. f = popen(cmd, "r");
  126. if (!f)
  127. return;
  128. do {
  129. start = fgets(buf, sizeof(buf), f);
  130. if (!start)
  131. continue;
  132. len = strlen(start);
  133. if (!tok)
  134. tok = json_tokener_new();
  135. obj = json_tokener_parse_ex(tok, start, len);
  136. if (obj) {
  137. netifd_init_script_handler(name, obj, cb);
  138. json_object_put(obj);
  139. json_tokener_free(tok);
  140. tok = NULL;
  141. } else if (start[len - 1] == '\n') {
  142. json_tokener_free(tok);
  143. tok = NULL;
  144. }
  145. } while (!feof(f) && !ferror(f));
  146. if (tok)
  147. json_tokener_free(tok);
  148. pclose(f);
  149. }
  150. static void
  151. netifd_parse_extdev_handler(const char *path_to_file, create_extdev_handler_cb cb)
  152. {
  153. struct json_tokener *tok = NULL;
  154. json_object *obj;
  155. FILE *file;
  156. int len;
  157. char buf[512], *start;
  158. file = fopen(path_to_file, "r");
  159. if (!file)
  160. return;
  161. do {
  162. start = fgets(buf, sizeof(buf), file);
  163. if (!start)
  164. continue;
  165. len = strlen(start);
  166. if (!tok)
  167. tok = json_tokener_new();
  168. obj = json_tokener_parse_ex(tok, start, len);
  169. if (obj) {
  170. netifd_init_extdev_handler(path_to_file, obj, cb);
  171. json_object_put(obj);
  172. json_tokener_free(tok);
  173. tok = NULL;
  174. } else if (start[len - 1] == '\n') {
  175. json_tokener_free(tok);
  176. tok = NULL;
  177. }
  178. } while (!feof(file) && !ferror(file));
  179. if (tok)
  180. json_tokener_free(tok);
  181. fclose(file);
  182. }
  183. void netifd_init_script_handlers(int dir_fd, script_dump_cb cb)
  184. {
  185. glob_t g;
  186. int prev_fd;
  187. size_t i;
  188. prev_fd = netifd_dir_push(dir_fd);
  189. if (glob("./*.sh", 0, NULL, &g)) {
  190. netifd_dir_pop(prev_fd);
  191. return;
  192. }
  193. for (i = 0; i < g.gl_pathc; i++)
  194. netifd_parse_script_handler(g.gl_pathv[i], cb);
  195. netifd_dir_pop(prev_fd);
  196. globfree(&g);
  197. }
  198. void
  199. netifd_init_extdev_handlers(int dir_fd, create_extdev_handler_cb cb)
  200. {
  201. glob_t g;
  202. int prev_fd;
  203. prev_fd = netifd_dir_push(dir_fd);
  204. glob("*.json", 0, NULL, &g);
  205. for (size_t i = 0; i < g.gl_pathc; i++)
  206. netifd_parse_extdev_handler(g.gl_pathv[i], cb);
  207. netifd_dir_pop(prev_fd);
  208. }
  209. char *
  210. netifd_handler_parse_config(struct uci_blob_param_list *config, json_object *obj)
  211. {
  212. struct blobmsg_policy *attrs;
  213. char *str_buf, *str_cur;
  214. char const **validate;
  215. int str_len = 0;
  216. int i;
  217. config->n_params = json_object_array_length(obj);
  218. attrs = calloc(1, sizeof(*attrs) * config->n_params);
  219. if (!attrs)
  220. return NULL;
  221. validate = calloc(1, sizeof(char*) * config->n_params);
  222. if (!validate)
  223. goto error;
  224. config->params = attrs;
  225. config->validate = validate;
  226. for (i = 0; i < config->n_params; i++) {
  227. json_object *cur, *name, *type;
  228. cur = json_check_type(json_object_array_get_idx(obj, i), json_type_array);
  229. if (!cur)
  230. goto error;
  231. name = json_check_type(json_object_array_get_idx(cur, 0), json_type_string);
  232. if (!name)
  233. goto error;
  234. type = json_check_type(json_object_array_get_idx(cur, 1), json_type_int);
  235. if (!type)
  236. goto error;
  237. attrs[i].name = json_object_get_string(name);
  238. attrs[i].type = json_object_get_int(type);
  239. if (attrs[i].type > BLOBMSG_TYPE_LAST)
  240. goto error;
  241. str_len += strlen(attrs[i].name) + 1;
  242. }
  243. str_buf = malloc(str_len);
  244. if (!str_buf)
  245. goto error;
  246. str_cur = str_buf;
  247. for (i = 0; i < config->n_params; i++) {
  248. const char *name = attrs[i].name;
  249. char *delim;
  250. attrs[i].name = str_cur;
  251. str_cur += sprintf(str_cur, "%s", name) + 1;
  252. delim = strchr(attrs[i].name, ':');
  253. if (delim) {
  254. *delim = '\0';
  255. validate[i] = ++delim;
  256. } else {
  257. validate[i] = NULL;
  258. }
  259. }
  260. return str_buf;
  261. error:
  262. free(attrs);
  263. if (validate)
  264. free(validate);
  265. config->n_params = 0;
  266. return NULL;
  267. }