add helper function for adding/removing devices to 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 #include <unistd.h>
20
21 #include "netifd.h"
22 #include "system.h"
23 #include "handler.h"
24
25 static int
26 netifd_dir_push(int fd)
27 {
28         int prev_fd = open(".", O_RDONLY | O_DIRECTORY);
29         system_fd_set_cloexec(prev_fd);
30         if (fd >= 0)
31                 fchdir(fd);
32         return prev_fd;
33 }
34
35 static void
36 netifd_dir_pop(int prev_fd)
37 {
38         fchdir(prev_fd);
39         close(prev_fd);
40 }
41
42 int netifd_open_subdir(const char *name)
43 {
44         int prev_dir;
45         int ret = -1;
46
47         prev_dir = netifd_dir_push(-1);
48         if (chdir(main_path)) {
49                 perror("chdir(main path)");
50                 goto out;
51         }
52
53         ret = open(name, O_RDONLY | O_DIRECTORY);
54         if (ret >= 0)
55                 system_fd_set_cloexec(ret);
56
57 out:
58         netifd_dir_pop(prev_dir);
59         return ret;
60 }
61
62 static void
63 netifd_init_script_handler(const char *script, json_object *obj, script_dump_cb cb)
64 {
65         json_object *tmp;
66         const char *name;
67
68         if (!json_check_type(obj, json_type_object))
69                 return;
70
71         tmp = json_get_field(obj, "name", json_type_string);
72         if (!tmp)
73                 return;
74
75         name = json_object_get_string(tmp);
76         cb(script, name, obj);
77 }
78
79 static void
80 netifd_parse_script_handler(const char *name, script_dump_cb cb)
81 {
82         struct json_tokener *tok = NULL;
83         json_object *obj;
84         static char buf[512];
85         char *start, *cmd;
86         FILE *f;
87         int len;
88
89 #define DUMP_SUFFIX     " '' dump"
90
91         cmd = alloca(strlen(name) + 1 + sizeof(DUMP_SUFFIX));
92         sprintf(cmd, "%s" DUMP_SUFFIX, name);
93
94         f = popen(cmd, "r");
95         if (!f)
96                 return;
97
98         do {
99                 start = fgets(buf, sizeof(buf), f);
100                 if (!start)
101                         continue;
102
103                 len = strlen(start);
104
105                 if (!tok)
106                         tok = json_tokener_new();
107
108                 obj = json_tokener_parse_ex(tok, start, len);
109                 if (!is_error(obj)) {
110                         netifd_init_script_handler(name, obj, cb);
111                         json_object_put(obj);
112                         json_tokener_free(tok);
113                         tok = NULL;
114                 } else if (start[len - 1] == '\n') {
115                         json_tokener_free(tok);
116                         tok = NULL;
117                 }
118         } while (!feof(f) && !ferror(f));
119
120         if (tok)
121                 json_tokener_free(tok);
122
123         pclose(f);
124 }
125
126 void netifd_init_script_handlers(int dir_fd, script_dump_cb cb)
127 {
128         glob_t g;
129         int i, prev_fd;
130
131         prev_fd = netifd_dir_push(dir_fd);
132         glob("./*.sh", 0, NULL, &g);
133         for (i = 0; i < g.gl_pathc; i++)
134                 netifd_parse_script_handler(g.gl_pathv[i], cb);
135         netifd_dir_pop(prev_fd);
136 }
137
138 char *
139 netifd_handler_parse_config(struct uci_blob_param_list *config, json_object *obj)
140 {
141         struct blobmsg_policy *attrs;
142         char *str_buf, *str_cur;
143         int str_len = 0;
144         int i;
145
146         config->n_params = json_object_array_length(obj);
147         attrs = calloc(1, sizeof(*attrs) * config->n_params);
148         if (!attrs)
149                 return NULL;
150
151         config->params = attrs;
152         for (i = 0; i < config->n_params; i++) {
153                 json_object *cur, *name, *type;
154
155                 cur = json_check_type(json_object_array_get_idx(obj, i), json_type_array);
156                 if (!cur)
157                         goto error;
158
159                 name = json_check_type(json_object_array_get_idx(cur, 0), json_type_string);
160                 if (!name)
161                         goto error;
162
163                 type = json_check_type(json_object_array_get_idx(cur, 1), json_type_int);
164                 if (!type)
165                         goto error;
166
167                 attrs[i].name = json_object_get_string(name);
168                 attrs[i].type = json_object_get_int(type);
169                 if (attrs[i].type > BLOBMSG_TYPE_LAST)
170                         goto error;
171
172                 str_len += strlen(attrs[i].name) + 1;
173         }
174
175         str_buf = malloc(str_len);
176         if (!str_buf)
177                 goto error;
178
179         str_cur = str_buf;
180         for (i = 0; i < config->n_params; i++) {
181                 const char *name = attrs[i].name;
182
183                 attrs[i].name = str_cur;
184                 str_cur += sprintf(str_cur, "%s", name) + 1;
185         }
186
187         return str_buf;
188
189 error:
190         free(attrs);
191         config->n_params = 0;
192         return NULL;
193 }