chiark / gitweb /
sd-network: allow the state dir to be created after the monitor
[elogind.git] / src / libelogind / sd-network / sd-network.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7   Copyright 2014 Tom Gundersen
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <string.h>
24 #include <errno.h>
25 #include <sys/inotify.h>
26 #include <poll.h>
27
28 #include "util.h"
29 #include "macro.h"
30 #include "strv.h"
31 #include "fileio.h"
32 #include "sd-network.h"
33
34 _public_ int sd_network_get_operational_state(char **state) {
35         _cleanup_free_ char *s = NULL;
36         int r;
37
38         assert_return(state, -EINVAL);
39
40         r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE", &s, NULL);
41         if (r == -ENOENT)
42                 return -ENODATA;
43         if (r < 0)
44                 return r;
45         if (isempty(s))
46                 return -ENODATA;
47
48         *state = s;
49         s = NULL;
50
51         return 0;
52 }
53
54 static int network_get_strv(const char *key, char ***ret) {
55         _cleanup_strv_free_ char **a = NULL;
56         _cleanup_free_ char *s = NULL;
57         int r;
58
59         assert_return(ret, -EINVAL);
60
61         r = parse_env_file("/run/systemd/netif/state", NEWLINE, key, &s, NULL);
62         if (r == -ENOENT)
63                 return -ENODATA;
64         if (r < 0)
65                 return r;
66         if (isempty(s)) {
67                 *ret = NULL;
68                 return 0;
69         }
70
71         a = strv_split(s, " ");
72         if (!a)
73                 return -ENOMEM;
74
75         strv_uniq(a);
76         r = strv_length(a);
77
78         *ret = a;
79         a = NULL;
80
81         return r;
82 }
83
84 _public_ int sd_network_get_dns(char ***ret) {
85         return network_get_strv("DNS", ret);
86 }
87
88 _public_ int sd_network_get_ntp(char ***ret) {
89         return network_get_strv("NTP", ret);
90 }
91
92 _public_ int sd_network_get_domains(char ***ret) {
93         return network_get_strv("DOMAINS", ret);
94 }
95
96 _public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
97         _cleanup_free_ char *s = NULL, *p = NULL;
98         int r;
99
100         assert_return(ifindex > 0, -EINVAL);
101         assert_return(state, -EINVAL);
102
103         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
104                 return -ENOMEM;
105
106         r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
107         if (r == -ENOENT)
108                 return -ENODATA;
109         if (r < 0)
110                 return r;
111         if (isempty(s))
112                 return -ENODATA;
113
114         *state = s;
115         s = NULL;
116
117         return 0;
118 }
119
120 _public_ int sd_network_link_get_network_file(int ifindex, char **filename) {
121         _cleanup_free_ char *s = NULL, *p = NULL;
122         int r;
123
124         assert_return(ifindex > 0, -EINVAL);
125         assert_return(filename, -EINVAL);
126
127         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
128                 return -ENOMEM;
129
130         r = parse_env_file(p, NEWLINE, "NETWORK_FILE", &s, NULL);
131         if (r == -ENOENT)
132                 return -ENODATA;
133         if (r < 0)
134                 return r;
135         if (isempty(s))
136                 return -ENODATA;
137
138         *filename = s;
139         s = NULL;
140
141         return 0;
142 }
143
144 _public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
145         _cleanup_free_ char *s = NULL, *p = NULL;
146         int r;
147
148         assert_return(ifindex > 0, -EINVAL);
149         assert_return(state, -EINVAL);
150
151         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
152                 return -ENOMEM;
153
154         r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
155         if (r == -ENOENT)
156                 return -ENODATA;
157         if (r < 0)
158                 return r;
159         if (isempty(s))
160                 return -ENODATA;
161
162         *state = s;
163         s = NULL;
164
165         return 0;
166 }
167
168 _public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
169         _cleanup_free_ char *s = NULL, *p = NULL;
170         int r;
171
172         assert_return(ifindex > 0, -EINVAL);
173         assert_return(llmnr, -EINVAL);
174
175         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
176                 return -ENOMEM;
177
178         r = parse_env_file(p, NEWLINE, "LLMNR", &s, NULL);
179         if (r == -ENOENT)
180                 return -ENODATA;
181         if (r < 0)
182                 return r;
183         if (isempty(s))
184                 return -ENODATA;
185
186         *llmnr = s;
187         s = NULL;
188
189         return 0;
190 }
191
192 _public_ int sd_network_link_get_lldp(int ifindex, char **lldp) {
193         _cleanup_free_ char *s = NULL, *p = NULL;
194         size_t size;
195         int r;
196
197         assert_return(ifindex > 0, -EINVAL);
198         assert_return(lldp, -EINVAL);
199
200         if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0)
201                 return -ENOMEM;
202
203         r = read_full_file(p, &s, &size);
204         if (r == -ENOENT)
205                 return -ENODATA;
206         if (r < 0)
207                 return r;
208         if (size <= 0)
209                 return -ENODATA;
210
211         *lldp = s;
212         s = NULL;
213
214         return 0;
215 }
216
217
218 static int network_get_link_strv(const char *key, int ifindex, char ***ret) {
219         _cleanup_free_ char *p = NULL, *s = NULL;
220         _cleanup_strv_free_ char **a = NULL;
221         int r;
222
223         assert_return(ifindex > 0, -EINVAL);
224         assert_return(ret, -EINVAL);
225
226         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
227                 return -ENOMEM;
228
229         r = parse_env_file(p, NEWLINE, key, &s, NULL);
230         if (r == -ENOENT)
231                 return -ENODATA;
232         if (r < 0)
233                 return r;
234         if (isempty(s)) {
235                 *ret = NULL;
236                 return 0;
237         }
238
239         a = strv_split(s, " ");
240         if (!a)
241                 return -ENOMEM;
242
243         strv_uniq(a);
244         r = strv_length(a);
245
246         *ret = a;
247         a = NULL;
248
249         return r;
250 }
251
252 _public_ int sd_network_link_get_dns(int ifindex, char ***ret) {
253         return network_get_link_strv("DNS", ifindex, ret);
254 }
255
256 _public_ int sd_network_link_get_ntp(int ifindex, char ***ret) {
257         return network_get_link_strv("NTP", ifindex, ret);
258 }
259
260 _public_ int sd_network_link_get_domains(int ifindex, char ***ret) {
261         return network_get_link_strv("DOMAINS", ifindex, ret);
262 }
263
264 _public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) {
265         return network_get_link_strv("CARRIER_BOUND_TO", ifindex, ret);
266 }
267
268 _public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) {
269         return network_get_link_strv("CARRIER_BOUND_BY", ifindex, ret);
270 }
271
272 _public_ int sd_network_link_get_wildcard_domain(int ifindex) {
273         int r;
274         _cleanup_free_ char *p = NULL, *s = NULL;
275
276         assert_return(ifindex > 0, -EINVAL);
277
278         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
279                 return -ENOMEM;
280
281         r = parse_env_file(p, NEWLINE, "WILDCARD_DOMAIN", &s, NULL);
282         if (r == -ENOENT)
283                 return -ENODATA;
284         if (r < 0)
285                 return r;
286         if (isempty(s))
287                 return -ENODATA;
288
289         return parse_boolean(s);
290 }
291
292 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
293         return (int) (unsigned long) m - 1;
294 }
295
296 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
297         return (sd_network_monitor*) (unsigned long) (fd + 1);
298 }
299
300 static int monitor_add_inotify_watch(int fd) {
301         int k;
302
303         k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
304         if (k >= 0)
305                 return 0;
306         else if (errno != ENOENT)
307                 return -errno;
308
309         k = inotify_add_watch(fd, "/run/systemd/netif/", IN_CREATE|IN_ISDIR);
310         if (k >= 0)
311                 return 0;
312         else if (errno != ENOENT)
313                 return -errno;
314
315         k = inotify_add_watch(fd, "/run/systemd/", IN_CREATE|IN_ISDIR);
316         if (k < 0)
317                 return -errno;
318
319         return 0;
320 }
321
322 _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
323         _cleanup_close_ int fd = -1;
324         int k;
325         bool good = false;
326
327         assert_return(m, -EINVAL);
328
329         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
330         if (fd < 0)
331                 return -errno;
332
333         if (!category || streq(category, "links")) {
334                 k = monitor_add_inotify_watch(fd);
335                 if (k < 0)
336                         return k;
337
338                 good = true;
339         }
340
341         if (!good) {
342                 close_nointr(fd);
343                 return -EINVAL;
344         }
345
346         *m = FD_TO_MONITOR(fd);
347         fd = -1;
348
349         return 0;
350 }
351
352 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
353         int fd;
354
355         if (m) {
356                 fd = MONITOR_TO_FD(m);
357                 close_nointr(fd);
358         }
359
360         return NULL;
361 }
362
363 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
364         union inotify_event_buffer buffer;
365         struct inotify_event *e;
366         ssize_t l;
367         int fd, k;
368
369         assert_return(m, -EINVAL);
370
371         fd = MONITOR_TO_FD(m);
372
373         l = read(fd, &buffer, sizeof(buffer));
374         if (l < 0) {
375                 if (errno == EAGAIN || errno == EINTR)
376                         return 0;
377
378                 return -errno;
379         }
380
381         FOREACH_INOTIFY_EVENT(e, buffer, l) {
382                 if (e->mask & IN_ISDIR) {
383                         k = monitor_add_inotify_watch(fd);
384                         if (k < 0)
385                                 return k;
386
387                         k = inotify_rm_watch(fd, e->wd);
388                         if (k < 0)
389                                 return -errno;
390                 }
391         }
392
393         return 0;
394 }
395
396 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
397
398         assert_return(m, -EINVAL);
399
400         return MONITOR_TO_FD(m);
401 }
402
403 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
404
405         assert_return(m, -EINVAL);
406
407         /* For now we will only return POLLIN here, since we don't
408          * need anything else ever for inotify.  However, let's have
409          * this API to keep our options open should we later on need
410          * it. */
411         return POLLIN;
412 }
413
414 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
415
416         assert_return(m, -EINVAL);
417         assert_return(timeout_usec, -EINVAL);
418
419         /* For now we will only return (uint64_t) -1, since we don't
420          * need any timeout. However, let's have this API to keep our
421          * options open should we later on need it. */
422         *timeout_usec = (uint64_t) -1;
423         return 0;
424 }