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