]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/sd-network.c
networkd-wait-online: track links
[thirdparty/systemd.git] / src / network / sd-network.c
CommitLineData
fe8db0c5
TG
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>
deb2e523 28#include <net/if.h>
fe8db0c5
TG
29
30#include "util.h"
31#include "macro.h"
32#include "strv.h"
33#include "fileio.h"
34#include "sd-network.h"
7dbf94a9 35#include "network-internal.h"
fe8db0c5
TG
36#include "dhcp-lease-internal.h"
37
deb2e523
TG
38static 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
85b5673b 45 if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
deb2e523
TG
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
fe8db0c5 70_public_ int sd_network_get_link_state(unsigned index, char **state) {
cb6fa44c 71 _cleanup_free_ char *s = NULL, *p = NULL;
fe8db0c5
TG
72 int r;
73
74 assert_return(index, -EINVAL);
75 assert_return(state, -EINVAL);
76
85b5673b 77 if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
fe8db0c5
TG
78 return -ENOMEM;
79
deb2e523 80 r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
cb6fa44c
TG
81 if (r == -ENOENT)
82 return -ENODATA;
83 else if (r < 0)
fe8db0c5 84 return r;
cb6fa44c 85 else if (!s)
fe8db0c5
TG
86 return -EIO;
87
560852ce 88 if (streq(s, "initializing"))
deb2e523
TG
89 return -EBUSY;
90
91 *state = s;
92 s = NULL;
93
94 return 0;
95}
96
bbf7c048
TG
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
85b5673b 103 r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE",
bbf7c048
TG
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
deb2e523
TG
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
85b5673b 125 if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
deb2e523
TG
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;
cb6fa44c 135
fe8db0c5 136 *state = s;
cb6fa44c
TG
137 s = NULL;
138
fe8db0c5
TG
139 return 0;
140}
141
142_public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
81d98a39 143 _cleanup_free_ char *p = NULL, *s = NULL;
68baa8fa 144 sd_dhcp_lease *lease = NULL;
fe8db0c5
TG
145 int r;
146
147 assert_return(index, -EINVAL);
148 assert_return(ret, -EINVAL);
149
85b5673b 150 if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
fe8db0c5
TG
151 return -ENOMEM;
152
153 r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
fe8db0c5 154
81d98a39 155 if (r < 0)
fe8db0c5 156 return r;
81d98a39 157 else if (!s)
fe8db0c5
TG
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
a2ba62c7 169static int network_get_in_addr(const char *key, unsigned index, struct in_addr **addr) {
7dbf94a9
TG
170 _cleanup_free_ char *p = NULL, *s = NULL;
171 int r;
172
173 assert_return(index, -EINVAL);
174 assert_return(addr, -EINVAL);
7dbf94a9 175
85b5673b 176 if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
7dbf94a9
TG
177 return -ENOMEM;
178
bcb7a07e 179 r = parse_env_file(p, NEWLINE, key, &s, NULL);
7dbf94a9
TG
180 if (r < 0)
181 return r;
182 else if (!s)
183 return -EIO;
184
a2ba62c7 185 return deserialize_in_addrs(addr, s);
7dbf94a9
TG
186}
187
a2ba62c7
LP
188_public_ int sd_network_get_dns(unsigned index, struct in_addr **addr) {
189 return network_get_in_addr("DNS", index, addr);
bcb7a07e
TG
190}
191
a2ba62c7
LP
192_public_ int sd_network_get_ntp(unsigned index, struct in_addr **addr) {
193 return network_get_in_addr("NTP", index, addr);
bcb7a07e
TG
194}
195
a2ba62c7 196static int network_get_in6_addr(const char *key, unsigned index, struct in6_addr **addr) {
7dbf94a9
TG
197 _cleanup_free_ char *p = NULL, *s = NULL;
198 int r;
199
200 assert_return(index, -EINVAL);
201 assert_return(addr, -EINVAL);
7dbf94a9 202
85b5673b 203 if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
7dbf94a9
TG
204 return -ENOMEM;
205
bcb7a07e 206 r = parse_env_file(p, NEWLINE, key, &s, NULL);
7dbf94a9
TG
207 if (r < 0)
208 return r;
209 else if (!s)
210 return -EIO;
211
a2ba62c7 212 return deserialize_in6_addrs(addr, s);
7dbf94a9
TG
213}
214
a2ba62c7
LP
215_public_ int sd_network_get_dns6(unsigned index, struct in6_addr **addr) {
216 return network_get_in6_addr("DNS", index, addr);
bcb7a07e
TG
217}
218
a2ba62c7
LP
219_public_ int sd_network_get_ntp6(unsigned index, struct in6_addr **addr) {
220 return network_get_in6_addr("NTP", index, addr);
bcb7a07e
TG
221}
222
223static int network_get_boolean(const char *key, unsigned index) {
7dbf94a9
TG
224 _cleanup_free_ char *p = NULL, *s = NULL;
225 int r;
226
227 assert_return(index, -EINVAL);
228
85b5673b 229 if (asprintf(&p, "/run/systemd/netif/links/%u", index) < 0)
7dbf94a9
TG
230 return -ENOMEM;
231
bcb7a07e 232 r = parse_env_file(p, NEWLINE, key, &s, NULL);
7dbf94a9
TG
233 if (r < 0)
234 return r;
235 else if (!s)
8b9652a7 236 return false;
7dbf94a9
TG
237
238 return parse_boolean(s);
239}
240
bcb7a07e
TG
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
fe8db0c5
TG
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
85b5673b 255 d = opendir("/run/systemd/netif/links/");
fe8db0c5
TG
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
307static inline int MONITOR_TO_FD(sd_network_monitor *m) {
308 return (int) (unsigned long) m - 1;
309}
310
311static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
312 return (sd_network_monitor*) (unsigned long) (fd + 1);
313}
314
0014a4ad 315_public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
fe8db0c5
TG
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
7e141e49 325 if (!category || streq(category, "links")) {
85b5673b 326 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
fe8db0c5 327 if (k < 0) {
03e334a1 328 safe_close(fd);
fe8db0c5
TG
329 return -errno;
330 }
331
332 good = true;
333 }
334
7e141e49 335 if (!category || streq(category, "leases")) {
85b5673b 336 k = inotify_add_watch(fd, "/run/systemd/netif/leases/", IN_MOVED_TO|IN_DELETE);
7e141e49
TG
337 if (k < 0) {
338 safe_close(fd);
339 return -errno;
340 }
341
342 good = true;
343 }
344
fe8db0c5
TG
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}