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