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