iprule: rework interface based rules to handle dynamic interfaces
[project/netifd.git] / handler.c
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_parse_script_handler(const char *name, script_dump_cb cb)
83 {
84 struct json_tokener *tok = NULL;
85 json_object *obj;
86 static char buf[512];
87 char *start, *cmd;
88 FILE *f;
89 int len;
90
91 #define DUMP_SUFFIX " '' dump"
92
93 cmd = alloca(strlen(name) + 1 + sizeof(DUMP_SUFFIX));
94 sprintf(cmd, "%s" DUMP_SUFFIX, name);
95
96 f = popen(cmd, "r");
97 if (!f)
98 return;
99
100 do {
101 start = fgets(buf, sizeof(buf), f);
102 if (!start)
103 continue;
104
105 len = strlen(start);
106
107 if (!tok)
108 tok = json_tokener_new();
109
110 obj = json_tokener_parse_ex(tok, start, len);
111 if (obj) {
112 netifd_init_script_handler(name, obj, cb);
113 json_object_put(obj);
114 json_tokener_free(tok);
115 tok = NULL;
116 } else if (start[len - 1] == '\n') {
117 json_tokener_free(tok);
118 tok = NULL;
119 }
120 } while (!feof(f) && !ferror(f));
121
122 if (tok)
123 json_tokener_free(tok);
124
125 pclose(f);
126 }
127
128 void netifd_init_script_handlers(int dir_fd, script_dump_cb cb)
129 {
130 glob_t g;
131 int i, prev_fd;
132
133 prev_fd = netifd_dir_push(dir_fd);
134 if (glob("./*.sh", 0, NULL, &g)) {
135 netifd_dir_pop(prev_fd);
136 return;
137 }
138
139 for (i = 0; i < g.gl_pathc; i++)
140 netifd_parse_script_handler(g.gl_pathv[i], cb);
141 netifd_dir_pop(prev_fd);
142
143 globfree(&g);
144 }
145
146 char *
147 netifd_handler_parse_config(struct uci_blob_param_list *config, json_object *obj)
148 {
149 struct blobmsg_policy *attrs;
150 char *str_buf, *str_cur;
151 char const **validate;
152 int str_len = 0;
153 int i;
154
155 config->n_params = json_object_array_length(obj);
156 attrs = calloc(1, sizeof(*attrs) * config->n_params);
157 if (!attrs)
158 return NULL;
159
160 validate = calloc(1, sizeof(char*) * config->n_params);
161 if (!validate)
162 goto error;
163
164 config->params = attrs;
165 config->validate = validate;
166 for (i = 0; i < config->n_params; i++) {
167 json_object *cur, *name, *type;
168
169 cur = json_check_type(json_object_array_get_idx(obj, i), json_type_array);
170 if (!cur)
171 goto error;
172
173 name = json_check_type(json_object_array_get_idx(cur, 0), json_type_string);
174 if (!name)
175 goto error;
176
177 type = json_check_type(json_object_array_get_idx(cur, 1), json_type_int);
178 if (!type)
179 goto error;
180
181 attrs[i].name = json_object_get_string(name);
182 attrs[i].type = json_object_get_int(type);
183 if (attrs[i].type > BLOBMSG_TYPE_LAST)
184 goto error;
185
186 str_len += strlen(attrs[i].name) + 1;
187 }
188
189 str_buf = malloc(str_len);
190 if (!str_buf)
191 goto error;
192
193 str_cur = str_buf;
194 for (i = 0; i < config->n_params; i++) {
195 const char *name = attrs[i].name;
196 char *delim;
197
198 attrs[i].name = str_cur;
199 str_cur += sprintf(str_cur, "%s", name) + 1;
200 delim = strchr(attrs[i].name, ':');
201 if (delim) {
202 *delim = '\0';
203 validate[i] = ++delim;
204 } else {
205 validate[i] = NULL;
206 }
207 }
208
209 return str_buf;
210
211 error:
212 free(attrs);
213 if (validate)
214 free(validate);
215 config->n_params = 0;
216 return NULL;
217 }