]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/sd-network.c
sd-network: fixup api
[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
6dcaa6f5 38_public_ int sd_network_get_link_state(int ifindex, char **state) {
deb2e523
TG
39 _cleanup_free_ char *s = NULL, *p = NULL;
40 int r;
41
6dcaa6f5 42 assert_return(ifindex > 0, -EINVAL);
fe8db0c5
TG
43 assert_return(state, -EINVAL);
44
6dcaa6f5 45 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
fe8db0c5
TG
46 return -ENOMEM;
47
deb2e523 48 r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
cb6fa44c
TG
49 if (r == -ENOENT)
50 return -ENODATA;
51 else if (r < 0)
fe8db0c5 52 return r;
cb6fa44c 53 else if (!s)
fe8db0c5
TG
54 return -EIO;
55
560852ce 56 if (streq(s, "initializing"))
deb2e523
TG
57 return -EBUSY;
58
59 *state = s;
60 s = NULL;
61
62 return 0;
63}
64
bbf7c048
TG
65_public_ int sd_network_get_operational_state(char **state) {
66 _cleanup_free_ char *s = NULL;
67 int r;
68
69 assert_return(state, -EINVAL);
70
85b5673b 71 r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE",
bbf7c048
TG
72 &s, NULL);
73 if (r == -ENOENT)
74 return -ENODATA;
75 else if (r < 0)
76 return r;
77 else if (!s)
78 return -EIO;
79
80 *state = s;
81 s = NULL;
82
83 return 0;
84}
85
6dcaa6f5 86_public_ int sd_network_get_link_operational_state(int ifindex, char **state) {
deb2e523
TG
87 _cleanup_free_ char *s = NULL, *p = NULL;
88 int r;
89
6dcaa6f5 90 assert_return(ifindex > 0, -EINVAL);
deb2e523
TG
91 assert_return(state, -EINVAL);
92
6dcaa6f5 93 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
deb2e523
TG
94 return -ENOMEM;
95
96 r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
97 if (r == -ENOENT)
98 return -ENODATA;
99 else if (r < 0)
100 return r;
101 else if (!s)
102 return -EIO;
cb6fa44c 103
fe8db0c5 104 *state = s;
cb6fa44c
TG
105 s = NULL;
106
fe8db0c5
TG
107 return 0;
108}
109
6dcaa6f5 110_public_ int sd_network_get_dhcp_lease(int ifindex, sd_dhcp_lease **ret) {
81d98a39 111 _cleanup_free_ char *p = NULL, *s = NULL;
68baa8fa 112 sd_dhcp_lease *lease = NULL;
fe8db0c5
TG
113 int r;
114
6dcaa6f5 115 assert_return(ifindex > 0, -EINVAL);
fe8db0c5
TG
116 assert_return(ret, -EINVAL);
117
6dcaa6f5 118 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
fe8db0c5
TG
119 return -ENOMEM;
120
121 r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
fe8db0c5 122
81d98a39 123 if (r < 0)
fe8db0c5 124 return r;
81d98a39 125 else if (!s)
fe8db0c5
TG
126 return -EIO;
127
128 r = dhcp_lease_load(s, &lease);
129 if (r < 0)
130 return r;
131
132 *ret = lease;
133
134 return 0;
135}
136
6dcaa6f5 137static int network_get_in_addr(const char *key, int ifindex, struct in_addr **addr) {
7dbf94a9
TG
138 _cleanup_free_ char *p = NULL, *s = NULL;
139 int r;
140
6dcaa6f5 141 assert_return(ifindex > 0, -EINVAL);
7dbf94a9 142 assert_return(addr, -EINVAL);
7dbf94a9 143
6dcaa6f5 144 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
7dbf94a9
TG
145 return -ENOMEM;
146
bcb7a07e 147 r = parse_env_file(p, NEWLINE, key, &s, NULL);
7dbf94a9
TG
148 if (r < 0)
149 return r;
150 else if (!s)
151 return -EIO;
152
a2ba62c7 153 return deserialize_in_addrs(addr, s);
7dbf94a9
TG
154}
155
6dcaa6f5
TG
156_public_ int sd_network_get_dns(int ifindex, struct in_addr **addr) {
157 return network_get_in_addr("DNS", ifindex, addr);
bcb7a07e
TG
158}
159
6dcaa6f5 160static int network_get_in6_addr(const char *key, int ifindex, struct in6_addr **addr) {
7dbf94a9
TG
161 _cleanup_free_ char *p = NULL, *s = NULL;
162 int r;
163
6dcaa6f5 164 assert_return(ifindex > 0, -EINVAL);
7dbf94a9 165 assert_return(addr, -EINVAL);
7dbf94a9 166
6dcaa6f5 167 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
7dbf94a9
TG
168 return -ENOMEM;
169
bcb7a07e 170 r = parse_env_file(p, NEWLINE, key, &s, NULL);
7dbf94a9
TG
171 if (r < 0)
172 return r;
173 else if (!s)
174 return -EIO;
175
a2ba62c7 176 return deserialize_in6_addrs(addr, s);
7dbf94a9
TG
177}
178
6dcaa6f5
TG
179_public_ int sd_network_get_dns6(int ifindex, struct in6_addr **addr) {
180 return network_get_in6_addr("DNS", ifindex, addr);
bcb7a07e
TG
181}
182
6dcaa6f5 183static int network_get_boolean(const char *key, int ifindex) {
7dbf94a9
TG
184 _cleanup_free_ char *p = NULL, *s = NULL;
185 int r;
186
6dcaa6f5 187 assert_return(ifindex > 0, -EINVAL);
7dbf94a9 188
6dcaa6f5 189 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
7dbf94a9
TG
190 return -ENOMEM;
191
bcb7a07e 192 r = parse_env_file(p, NEWLINE, key, &s, NULL);
7dbf94a9
TG
193 if (r < 0)
194 return r;
195 else if (!s)
8b9652a7 196 return false;
7dbf94a9
TG
197
198 return parse_boolean(s);
199}
200
6dcaa6f5
TG
201_public_ int sd_network_dhcp_use_dns(int ifindex) {
202 return network_get_boolean("DHCP_USE_DNS", ifindex);
bcb7a07e
TG
203}
204
6dcaa6f5
TG
205_public_ int sd_network_dhcp_use_ntp(int ifindex) {
206 return network_get_boolean("DHCP_USE_NTP", ifindex);
bcb7a07e
TG
207}
208
6dcaa6f5 209_public_ int sd_network_get_ifindices(int **ifindices) {
fe8db0c5
TG
210 _cleanup_closedir_ DIR *d;
211 int r = 0;
212 unsigned n = 0;
6dcaa6f5 213 _cleanup_free_ int *l = NULL;
fe8db0c5 214
85b5673b 215 d = opendir("/run/systemd/netif/links/");
fe8db0c5
TG
216 if (!d)
217 return -errno;
218
219 for (;;) {
220 struct dirent *de;
221 int k;
6dcaa6f5 222 int ifindex;
fe8db0c5
TG
223
224 errno = 0;
225 de = readdir(d);
226 if (!de && errno != 0)
227 return -errno;
228
229 if (!de)
230 break;
231
232 dirent_ensure_type(d, de);
233
234 if (!dirent_is_file(de))
235 continue;
236
6dcaa6f5 237 k = safe_atoi(de->d_name, &ifindex);
fe8db0c5
TG
238 if (k < 0)
239 continue;
240
6dcaa6f5 241 if (ifindices) {
fe8db0c5 242 if ((unsigned) r >= n) {
6dcaa6f5 243 int *t;
fe8db0c5
TG
244
245 n = MAX(16, 2*r);
6dcaa6f5 246 t = realloc(l, sizeof(int) * n);
fe8db0c5
TG
247 if (!t)
248 return -ENOMEM;
249
250 l = t;
251 }
252
253 assert((unsigned) r < n);
6dcaa6f5 254 l[r++] = ifindex;
fe8db0c5
TG
255 } else
256 r++;
257 }
258
6dcaa6f5
TG
259 if (ifindices) {
260 *ifindices = l;
fe8db0c5
TG
261 l = NULL;
262 }
263
264 return r;
265}
266
267static inline int MONITOR_TO_FD(sd_network_monitor *m) {
268 return (int) (unsigned long) m - 1;
269}
270
271static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
272 return (sd_network_monitor*) (unsigned long) (fd + 1);
273}
274
0014a4ad 275_public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
fe8db0c5
TG
276 int fd, k;
277 bool good = false;
278
279 assert_return(m, -EINVAL);
280
281 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
282 if (fd < 0)
283 return -errno;
284
7e141e49 285 if (!category || streq(category, "links")) {
85b5673b 286 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
fe8db0c5 287 if (k < 0) {
03e334a1 288 safe_close(fd);
fe8db0c5
TG
289 return -errno;
290 }
291
292 good = true;
293 }
294
7e141e49 295 if (!category || streq(category, "leases")) {
85b5673b 296 k = inotify_add_watch(fd, "/run/systemd/netif/leases/", IN_MOVED_TO|IN_DELETE);
7e141e49
TG
297 if (k < 0) {
298 safe_close(fd);
299 return -errno;
300 }
301
302 good = true;
303 }
304
fe8db0c5
TG
305 if (!good) {
306 close_nointr(fd);
307 return -EINVAL;
308 }
309
310 *m = FD_TO_MONITOR(fd);
311 return 0;
312}
313
314_public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
315 int fd;
316
317 assert_return(m, NULL);
318
319 fd = MONITOR_TO_FD(m);
320 close_nointr(fd);
321
322 return NULL;
323}
324
325_public_ int sd_network_monitor_flush(sd_network_monitor *m) {
326
327 assert_return(m, -EINVAL);
328
329 return flush_fd(MONITOR_TO_FD(m));
330}
331
332_public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
333
334 assert_return(m, -EINVAL);
335
336 return MONITOR_TO_FD(m);
337}
338
339_public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
340
341 assert_return(m, -EINVAL);
342
343 /* For now we will only return POLLIN here, since we don't
344 * need anything else ever for inotify. However, let's have
345 * this API to keep our options open should we later on need
346 * it. */
347 return POLLIN;
348}
349
350_public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
351
352 assert_return(m, -EINVAL);
353 assert_return(timeout_usec, -EINVAL);
354
355 /* For now we will only return (uint64_t) -1, since we don't
356 * need any timeout. However, let's have this API to keep our
357 * options open should we later on need it. */
358 *timeout_usec = (uint64_t) -1;
359 return 0;
360}