handler.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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 i, prev_fd;
  187. prev_fd = netifd_dir_push(dir_fd);
  188. if (glob("./*.sh", 0, NULL, &g)) {
  189. netifd_dir_pop(prev_fd);
  190. return;
  191. }
  192. for (i = 0; i < g.gl_pathc; i++)
  193. netifd_parse_script_handler(g.gl_pathv[i], cb);
  194. netifd_dir_pop(prev_fd);
  195. globfree(&g);
  196. }
  197. void
  198. netifd_init_extdev_handlers(int dir_fd, create_extdev_handler_cb cb)
  199. {
  200. glob_t g;
  201. int prev_fd;
  202. prev_fd = netifd_dir_push(dir_fd);
  203. glob("*.json", 0, NULL, &g);
  204. for (int i = 0; i < g.gl_pathc; i++)
  205. netifd_parse_extdev_handler(g.gl_pathv[i], cb);
  206. netifd_dir_pop(prev_fd);
  207. }
  208. char *
  209. netifd_handler_parse_config(struct uci_blob_param_list *config, json_object *obj)
  210. {
  211. struct blobmsg_policy *attrs;
  212. char *str_buf, *str_cur;
  213. char const **validate;
  214. int str_len = 0;
  215. int i;
  216. config->n_params = json_object_array_length(obj);
  217. attrs = calloc(1, sizeof(*attrs) * config->n_params);
  218. if (!attrs)
  219. return NULL;
  220. validate = calloc(1, sizeof(char*) * config->n_params);
  221. if (!validate)
  222. goto error;
  223. config->params = attrs;
  224. config->validate = validate;
  225. for (i = 0; i < config->n_params; i++) {
  226. json_object *cur, *name, *type;
  227. cur = json_check_type(json_object_array_get_idx(obj, i), json_type_array);
  228. if (!cur)
  229. goto error;
  230. name = json_check_type(json_object_array_get_idx(cur, 0), json_type_string);
  231. if (!name)
  232. goto error;
  233. type = json_check_type(json_object_array_get_idx(cur, 1), json_type_int);
  234. if (!type)
  235. goto error;
  236. attrs[i].name = json_object_get_string(name);
  237. attrs[i].type = json_object_get_int(type);
  238. if (attrs[i].type > BLOBMSG_TYPE_LAST)
  239. goto error;
  240. str_len += strlen(attrs[i].name) + 1;
  241. }
  242. str_buf = malloc(str_len);
  243. if (!str_buf)
  244. goto error;
  245. str_cur = str_buf;
  246. for (i = 0; i < config->n_params; i++) {
  247. const char *name = attrs[i].name;
  248. char *delim;
  249. attrs[i].name = str_cur;
  250. str_cur += sprintf(str_cur, "%s", name) + 1;
  251. delim = strchr(attrs[i].name, ':');
  252. if (delim) {
  253. *delim = '\0';
  254. validate[i] = ++delim;
  255. } else {
  256. validate[i] = NULL;
  257. }
  258. }
  259. return str_buf;
  260. error:
  261. free(attrs);
  262. if (validate)
  263. free(validate);
  264. config->n_params = 0;
  265. return NULL;
  266. }