chiark / gitweb /
sd-network: if a boolean is mising, we should just take it as false
[elogind.git] / src / 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 <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <sys/inotify.h>
27 #include <sys/poll.h>
28 #include <net/if.h>
29
30 #include "util.h"
31 #include "macro.h"
32 #include "strv.h"
33 #include "fileio.h"
34 #include "sd-network.h"
35 #include "network-internal.h"
36 #include "dhcp-lease-internal.h"
37
38 static int link_get_flags(unsigned index, unsigned *flags) {
39         _cleanup_free_ char *s = NULL, *p = NULL;
40         int r;
41
42         assert(index);
43         assert(flags);
44
45         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
46                 return -ENOMEM;
47
48         r = parse_env_file(p, NEWLINE, "FLAGS", &s, NULL);
49         if (r == -ENOENT)
50                 return -ENODATA;
51         else if (r < 0)
52                 return r;
53         else if (!s)
54                 return -EIO;
55
56         return safe_atou(s, flags);
57 }
58
59 _public_ int sd_network_link_is_loopback(unsigned index) {
60         unsigned flags;
61         int r;
62
63         r = link_get_flags(index, &flags);
64         if (r < 0)
65                 return 0;
66
67         return flags & IFF_LOOPBACK;
68 }
69
70 _public_ int sd_network_get_link_state(unsigned index, char **state) {
71         _cleanup_free_ char *s = NULL, *p = NULL;
72         int r;
73
74         assert_return(index, -EINVAL);
75         assert_return(state, -EINVAL);
76
77         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
78                 return -ENOMEM;
79
80         r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
81         if (r == -ENOENT)
82                 return -ENODATA;
83         else if (r < 0)
84                 return r;
85         else if (!s)
86                 return -EIO;
87
88         if (streq(s, "unmanaged"))
89                 return -EUNATCH;
90         else if (streq(s, "initializing"))
91                 return -EBUSY;
92
93         *state = s;
94         s = NULL;
95
96         return 0;
97 }
98
99 _public_ int sd_network_get_operational_state(char **state) {
100         _cleanup_free_ char *s = NULL;
101         int r;
102
103         assert_return(state, -EINVAL);
104
105         r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE",
106                            &s, NULL);
107         if (r == -ENOENT)
108                 return -ENODATA;
109         else if (r < 0)
110                 return r;
111         else if (!s)
112                 return -EIO;
113
114         *state = s;
115         s = NULL;
116
117         return 0;
118 }
119
120 _public_ int sd_network_get_link_operational_state(unsigned index, char **state) {
121         _cleanup_free_ char *s = NULL, *p = NULL;
122         int r;
123
124         assert_return(index, -EINVAL);
125         assert_return(state, -EINVAL);
126
127         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
128                 return -ENOMEM;
129
130         r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
131         if (r == -ENOENT)
132                 return -ENODATA;
133         else if (r < 0)
134                 return r;
135         else if (!s)
136                 return -EIO;
137
138         *state = s;
139         s = NULL;
140
141         return 0;
142 }
143
144 _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
145         _cleanup_free_ char *p = NULL, *s = NULL;
146         sd_dhcp_lease *lease = NULL;
147         int r;
148
149         assert_return(index, -EINVAL);
150         assert_return(ret, -EINVAL);
151
152         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
153                 return -ENOMEM;
154
155         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
156
157         if (r < 0)
158                 return r;
159         else if (!s)
160                 return -EIO;
161
162         r = dhcp_lease_load(s, &lease);
163         if (r < 0)
164                 return r;
165
166         *ret = lease;
167
168         return 0;
169 }
170
171 static int network_get_in_addr(const char *key, unsigned index, struct in_addr **addr) {
172         _cleanup_free_ char *p = NULL, *s = NULL;
173         int r;
174
175         assert_return(index, -EINVAL);
176         assert_return(addr, -EINVAL);
177
178         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
179                 return -ENOMEM;
180
181         r = parse_env_file(p, NEWLINE, key, &s, NULL);
182         if (r < 0)
183                 return r;
184         else if (!s)
185                 return -EIO;
186
187         return deserialize_in_addrs(addr, s);
188 }
189
190 _public_ int sd_network_get_dns(unsigned index, struct in_addr **addr) {
191         return network_get_in_addr("DNS", index, addr);
192 }
193
194 _public_ int sd_network_get_ntp(unsigned index, struct in_addr **addr) {
195         return network_get_in_addr("NTP", index, addr);
196 }
197
198 static int network_get_in6_addr(const char *key, unsigned index, struct in6_addr **addr) {
199         _cleanup_free_ char *p = NULL, *s = NULL;
200         int r;
201
202         assert_return(index, -EINVAL);
203         assert_return(addr, -EINVAL);
204
205         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
206                 return -ENOMEM;
207
208         r = parse_env_file(p, NEWLINE, key, &s, NULL);
209         if (r < 0)
210                 return r;
211         else if (!s)
212                 return -EIO;
213
214         return deserialize_in6_addrs(addr, s);
215 }
216
217 _public_ int sd_network_get_dns6(unsigned index, struct in6_addr **addr) {
218         return network_get_in6_addr("DNS", index, addr);
219 }
220
221 _public_ int sd_network_get_ntp6(unsigned index, struct in6_addr **addr) {
222         return network_get_in6_addr("NTP", index, addr);
223 }
224
225 static int network_get_boolean(const char *key, unsigned index) {
226         _cleanup_free_ char *p = NULL, *s = NULL;
227         int r;
228
229         assert_return(index, -EINVAL);
230
231         if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
232                 return -ENOMEM;
233
234         r = parse_env_file(p, NEWLINE, key, &s, NULL);
235         if (r < 0)
236                 return r;
237         else if (!s)
238                 return false;
239
240         return parse_boolean(s);
241 }
242
243 _public_ int sd_network_dhcp_use_dns(unsigned index) {
244         return network_get_boolean("DHCP_USE_DNS", index);
245 }
246
247 _public_ int sd_network_dhcp_use_ntp(unsigned index) {
248         return network_get_boolean("DHCP_USE_NTP", index);
249 }
250
251 _public_ int sd_network_get_ifindices(unsigned **indices) {
252         _cleanup_closedir_ DIR *d;
253         int r = 0;
254         unsigned n = 0;
255         _cleanup_free_ uid_t *l = NULL;
256
257         d = opendir("/run/systemd/netif/links/");
258         if (!d)
259                 return -errno;
260
261         for (;;) {
262                 struct dirent *de;
263                 int k;
264                 unsigned index;
265
266                 errno = 0;
267                 de = readdir(d);
268                 if (!de && errno != 0)
269                         return -errno;
270
271                 if (!de)
272                         break;
273
274                 dirent_ensure_type(d, de);
275
276                 if (!dirent_is_file(de))
277                         continue;
278
279                 k = safe_atou(de->d_name, &index);
280                 if (k < 0)
281                         continue;
282
283                 if (indices) {
284                         if ((unsigned) r >= n) {
285                                 unsigned *t;
286
287                                 n = MAX(16, 2*r);
288                                 t = realloc(l, sizeof(unsigned) * n);
289                                 if (!t)
290                                         return -ENOMEM;
291
292                                 l = t;
293                         }
294
295                         assert((unsigned) r < n);
296                         l[r++] = index;
297                 } else
298                         r++;
299         }
300
301         if (indices) {
302                 *indices = l;
303                 l = NULL;
304         }
305
306         return r;
307 }
308
309 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
310         return (int) (unsigned long) m - 1;
311 }
312
313 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
314         return (sd_network_monitor*) (unsigned long) (fd + 1);
315 }
316
317 _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
318         int fd, k;
319         bool good = false;
320
321         assert_return(m, -EINVAL);
322
323         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
324         if (fd < 0)
325                 return -errno;
326
327         if (!category || streq(category, "links")) {
328                 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
329                 if (k < 0) {
330                         safe_close(fd);
331                         return -errno;
332                 }
333
334                 good = true;
335         }
336
337         if (!category || streq(category, "leases")) {
338                 k = inotify_add_watch(fd, "/run/systemd/netif/leases/", IN_MOVED_TO|IN_DELETE);
339                 if (k < 0) {
340                         safe_close(fd);
341                         return -errno;
342                 }
343
344                 good = true;
345         }
346
347         if (!good) {
348                 close_nointr(fd);
349                 return -EINVAL;
350         }
351
352         *m = FD_TO_MONITOR(fd);
353         return 0;
354 }
355
356 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
357         int fd;
358
359         assert_return(m, NULL);
360
361         fd = MONITOR_TO_FD(m);
362         close_nointr(fd);
363
364         return NULL;
365 }
366
367 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
368
369         assert_return(m, -EINVAL);
370
371         return flush_fd(MONITOR_TO_FD(m));
372 }
373
374 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
375
376         assert_return(m, -EINVAL);
377
378         return MONITOR_TO_FD(m);
379 }
380
381 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
382
383         assert_return(m, -EINVAL);
384
385         /* For now we will only return POLLIN here, since we don't
386          * need anything else ever for inotify.  However, let's have
387          * this API to keep our options open should we later on need
388          * it. */
389         return POLLIN;
390 }
391
392 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
393
394         assert_return(m, -EINVAL);
395         assert_return(timeout_usec, -EINVAL);
396
397         /* For now we will only return (uint64_t) -1, since we don't
398          * need any timeout. However, let's have this API to keep our
399          * options open should we later on need it. */
400         *timeout_usec = (uint64_t) -1;
401         return 0;
402 }