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 15 #define _GNU_SOURCE 16 #include <glob.h> 17 #include <fcntl.h> 18 #include <stdio.h> 19 20 #include "netifd.h" 21 #include "system.h" 22 #include "handler.h" 23 24 static int 25 netifd_dir_push(int fd) 26 { 27 int prev_fd = open(".", O_RDONLY | O_DIRECTORY); 28 system_fd_set_cloexec(prev_fd); 29 if (fd >= 0) 30 if (fchdir(fd)) {} 31 return prev_fd; 32 } 33 34 static void 35 netifd_dir_pop(int prev_fd) 36 { 37 if (prev_fd < 0) 38 return; 39 40 if (fchdir(prev_fd)) {} 41 close(prev_fd); 42 } 43 44 int netifd_open_subdir(const char *name) 45 { 46 int prev_dir; 47 int ret = -1; 48 49 prev_dir = netifd_dir_push(-1); 50 if (chdir(main_path)) { 51 perror("chdir(main path)"); 52 goto out; 53 } 54 55 ret = open(name, O_RDONLY | O_DIRECTORY); 56 if (ret >= 0) 57 system_fd_set_cloexec(ret); 58 59 out: 60 netifd_dir_pop(prev_dir); 61 return ret; 62 } 63 64 static void 65 netifd_init_script_handler(const char *script, json_object *obj, script_dump_cb cb) 66 { 67 json_object *tmp; 68 const char *name; 69 70 if (!json_check_type(obj, json_type_object)) 71 return; 72 73 tmp = json_get_field(obj, "name", json_type_string); 74 if (!tmp) 75 return; 76 77 name = json_object_get_string(tmp); 78 cb(script, name, obj); 79 } 80 81 static void 82 netifd_init_extdev_handler(const char *config_file, json_object *obj, 83 create_extdev_handler_cb cb) 84 { 85 json_object *tmp, *cfg, *info, *stats; 86 const char *name, *ubus_name, *br_prefix = NULL; 87 bool bridge_support = true; 88 char *err_missing; 89 90 if (!json_check_type(obj, json_type_object)) 91 return; 92 93 tmp = json_get_field(obj, "name", json_type_string); 94 if (!tmp) { 95 err_missing = "name"; 96 goto field_missing; 97 } 98 99 name = json_object_get_string(tmp); 100 101 tmp = json_get_field(obj, "ubus_name", json_type_string); 102 if (!tmp) { 103 err_missing = "ubus_name"; 104 goto field_missing; 105 } 106 107 ubus_name = json_object_get_string(tmp); 108 109 tmp = json_get_field(obj, "bridge", json_type_string); 110 if (!tmp || !strcmp(json_object_get_string(tmp), "")) 111 bridge_support = false; 112 113 if (bridge_support) { 114 tmp = json_get_field(obj, "br-prefix", json_type_string); 115 if (!tmp) 116 br_prefix = name; 117 else 118 br_prefix = json_object_get_string(tmp); 119 } 120 121 tmp = json_get_field(obj, "config", json_type_array); 122 if (!tmp) { 123 err_missing = "config"; 124 goto field_missing; 125 } 126 127 cfg = tmp; 128 129 info = json_get_field(obj, "info", json_type_array); 130 stats = json_get_field(obj, "stats", json_type_array); 131 132 cb(config_file, name, ubus_name, bridge_support, br_prefix, cfg, info, stats); 133 return; 134 135 field_missing: 136 netifd_log_message(L_WARNING, "external device handler description '%s' is" 137 "missing field '%s'\n", config_file, err_missing); 138 } 139 140 static void 141 netifd_parse_script_handler(const char *name, script_dump_cb cb) 142 { 143 struct json_tokener *tok = NULL; 144 json_object *obj; 145 static char buf[512]; 146 char *start, *cmd; 147 FILE *f; 148 int len; 149 150 #define DUMP_SUFFIX " '' dump" 151 152 cmd = alloca(strlen(name) + 1 + sizeof(DUMP_SUFFIX)); 153 sprintf(cmd, "%s" DUMP_SUFFIX, name); 154 155 f = popen(cmd, "r"); 156 if (!f) 157 return; 158 159 do { 160 start = fgets(buf, sizeof(buf), f); 161 if (!start) 162 continue; 163 164 len = strlen(start); 165 if (!len) 166 continue; 167 168 if (!tok) 169 tok = json_tokener_new(); 170 171 obj = json_tokener_parse_ex(tok, start, len); 172 if (obj) { 173 netifd_init_script_handler(name, obj, cb); 174 json_object_put(obj); 175 json_tokener_free(tok); 176 tok = NULL; 177 } else if (start[len - 1] == '\n') { 178 json_tokener_free(tok); 179 tok = NULL; 180 } 181 } while (!feof(f) && !ferror(f)); 182 183 if (tok) 184 json_tokener_free(tok); 185 186 pclose(f); 187 } 188 189 static void 190 netifd_parse_extdev_handler(const char *path_to_file, create_extdev_handler_cb cb) 191 { 192 struct json_tokener *tok = NULL; 193 json_object *obj; 194 FILE *file; 195 int len; 196 char buf[512], *start; 197 198 file = fopen(path_to_file, "r"); 199 if (!file) 200 return; 201 202 do { 203 start = fgets(buf, sizeof(buf), file); 204 if (!start) 205 continue; 206 207 len = strlen(start); 208 if (!len) 209 continue; 210 211 if (!tok) 212 tok = json_tokener_new(); 213 214 obj = json_tokener_parse_ex(tok, start, len); 215 216 if (obj) { 217 netifd_init_extdev_handler(path_to_file, obj, cb); 218 json_object_put(obj); 219 json_tokener_free(tok); 220 tok = NULL; 221 } else if (start[len - 1] == '\n') { 222 json_tokener_free(tok); 223 tok = NULL; 224 } 225 } while (!feof(file) && !ferror(file)); 226 227 if (tok) 228 json_tokener_free(tok); 229 230 fclose(file); 231 } 232 233 void netifd_init_script_handlers(int dir_fd, script_dump_cb cb) 234 { 235 glob_t g; 236 int prev_fd; 237 size_t i; 238 239 prev_fd = netifd_dir_push(dir_fd); 240 if (glob("./*.sh", 0, NULL, &g)) { 241 netifd_dir_pop(prev_fd); 242 return; 243 } 244 245 for (i = 0; i < g.gl_pathc; i++) 246 netifd_parse_script_handler(g.gl_pathv[i], cb); 247 netifd_dir_pop(prev_fd); 248 249 globfree(&g); 250 } 251 252 void 253 netifd_init_extdev_handlers(int dir_fd, create_extdev_handler_cb cb) 254 { 255 glob_t g; 256 int prev_fd; 257 258 prev_fd = netifd_dir_push(dir_fd); 259 if (glob("*.json", 0, NULL, &g)) { 260 netifd_dir_pop(prev_fd); 261 return; 262 } 263 264 for (size_t i = 0; i < g.gl_pathc; i++) 265 netifd_parse_extdev_handler(g.gl_pathv[i], cb); 266 netifd_dir_pop(prev_fd); 267 268 globfree(&g); 269 } 270 271 void 272 netifd_handler_free_config(struct uci_blob_param_list *config) 273 { 274 free((void *)config->params); 275 free((void *)config->validate); 276 config->params = NULL; 277 config->validate = NULL; 278 config->n_params = 0; 279 } 280 281 char * 282 netifd_handler_parse_config(struct uci_blob_param_list *config, json_object *obj) 283 { 284 struct blobmsg_policy *attrs; 285 char *str_buf, *str_cur; 286 char const **validate; 287 int str_len = 0; 288 int i; 289 290 config->n_params = json_object_array_length(obj); 291 config->params = attrs = calloc(1, sizeof(*attrs) * config->n_params); 292 if (!attrs) 293 goto error; 294 295 config->validate = validate = calloc(1, sizeof(char*) * config->n_params); 296 if (!validate) 297 goto error; 298 for (i = 0; i < config->n_params; i++) { 299 json_object *cur, *name, *type; 300 int type_val; 301 302 cur = json_check_type(json_object_array_get_idx(obj, i), json_type_array); 303 if (!cur) 304 goto error; 305 306 name = json_check_type(json_object_array_get_idx(cur, 0), json_type_string); 307 if (!name) 308 goto error; 309 310 type = json_check_type(json_object_array_get_idx(cur, 1), json_type_int); 311 if (!type) 312 goto error; 313 314 type_val = json_object_get_int(type); 315 if (type_val < 0 || type_val > BLOBMSG_TYPE_LAST) 316 goto error; 317 318 attrs[i].name = json_object_get_string(name); 319 attrs[i].type = type_val; 320 321 str_len += strlen(attrs[i].name) + 1; 322 } 323 324 str_buf = malloc(str_len); 325 if (!str_buf) 326 goto error; 327 328 str_cur = str_buf; 329 for (i = 0; i < config->n_params; i++) { 330 const char *name = attrs[i].name; 331 char *dest = str_cur; 332 char *delim; 333 334 attrs[i].name = dest; 335 str_cur += sprintf(dest, "%s", name) + 1; 336 delim = strchr(dest, ':'); 337 if (delim) { 338 *delim = '\0'; 339 validate[i] = ++delim; 340 } else { 341 validate[i] = NULL; 342 } 343 } 344 345 return str_buf; 346 347 error: 348 netifd_handler_free_config(config); 349 return NULL; 350 } 351
This page was automatically generated by LXR 0.3.1. • OpenWrt