chiark / gitweb /
0844e58686191dc74e2014335f138ca2720e03f8
[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 _public_ int sd_network_get_link_state(int ifindex, char **state) {
39         _cleanup_free_ char *s = NULL, *p = NULL;
40         int r;
41
42         assert_return(ifindex > 0, -EINVAL);
43         assert_return(state, -EINVAL);
44
45         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
46                 return -ENOMEM;
47
48         r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &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         if (streq(s, "initializing"))
57                 return -EBUSY;
58
59         *state = s;
60         s = NULL;
61
62         return 0;
63 }
64
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
71         r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE",
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
86 _public_ int sd_network_get_link_operational_state(int ifindex, char **state) {
87         _cleanup_free_ char *s = NULL, *p = NULL;
88         int r;
89
90         assert_return(ifindex > 0, -EINVAL);
91         assert_return(state, -EINVAL);
92
93         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
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;
103
104         *state = s;
105         s = NULL;
106
107         return 0;
108 }
109
110 _public_ int sd_network_get_dhcp_lease(int ifindex, sd_dhcp_lease **ret) {
111         _cleanup_free_ char *p = NULL, *s = NULL;
112         sd_dhcp_lease *lease = NULL;
113         int r;
114
115         assert_return(ifindex > 0, -EINVAL);
116         assert_return(ret, -EINVAL);
117
118         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
119                 return -ENOMEM;
120
121         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
122
123         if (r < 0)
124                 return r;
125         else if (!s)
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
137 static int network_get_in_addr(const char *key, int ifindex, struct in_addr **addr) {
138         _cleanup_free_ char *p = NULL, *s = NULL;
139         int r;
140
141         assert_return(ifindex > 0, -EINVAL);
142         assert_return(addr, -EINVAL);
143
144         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
145                 return -ENOMEM;
146
147         r = parse_env_file(p, NEWLINE, key, &s, NULL);
148         if (r < 0)
149                 return r;
150         else if (!s)
151                 return -EIO;
152
153         return deserialize_in_addrs(addr, s);
154 }
155
156 _public_ int sd_network_get_dns(int ifindex, struct in_addr **addr) {
157         return network_get_in_addr("DNS", ifindex, addr);
158 }
159
160 static int network_get_in6_addr(const char *key, int ifindex, struct in6_addr **addr) {
161         _cleanup_free_ char *p = NULL, *s = NULL;
162         int r;
163
164         assert_return(ifindex > 0, -EINVAL);
165         assert_return(addr, -EINVAL);
166
167         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
168                 return -ENOMEM;
169
170         r = parse_env_file(p, NEWLINE, key, &s, NULL);
171         if (r < 0)
172                 return r;
173         else if (!s)
174                 return -EIO;
175
176         return deserialize_in6_addrs(addr, s);
177 }
178
179 _public_ int sd_network_get_dns6(int ifindex, struct in6_addr **addr) {
180         return network_get_in6_addr("DNS", ifindex, addr);
181 }
182
183 static int network_get_boolean(const char *key, int ifindex) {
184         _cleanup_free_ char *p = NULL, *s = NULL;
185         int r;
186
187         assert_return(ifindex > 0, -EINVAL);
188
189         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
190                 return -ENOMEM;
191
192         r = parse_env_file(p, NEWLINE, key, &s, NULL);
193         if (r < 0)
194                 return r;
195         else if (!s)
196                 return false;
197
198         return parse_boolean(s);
199 }
200
201 _public_ int sd_network_dhcp_use_dns(int ifindex) {
202         return network_get_boolean("DHCP_USE_DNS", ifindex);
203 }
204
205 _public_ int sd_network_dhcp_use_ntp(int ifindex) {
206         return network_get_boolean("DHCP_USE_NTP", ifindex);
207 }
208
209 _public_ int sd_network_get_ifindices(int **ifindices) {
210         _cleanup_closedir_ DIR *d;
211         int r = 0;
212         unsigned n = 0;
213         _cleanup_free_ int *l = NULL;
214
215         d = opendir("/run/systemd/netif/links/");
216         if (!d)
217                 return -errno;
218
219         for (;;) {
220                 struct dirent *de;
221                 int k;
222                 int ifindex;
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
237                 k = safe_atoi(de->d_name, &ifindex);
238                 if (k < 0)
239                         continue;
240
241                 if (ifindices) {
242                         if ((unsigned) r >= n) {
243                                 int *t;
244
245                                 n = MAX(16, 2*r);
246                                 t = realloc(l, sizeof(int) * n);
247                                 if (!t)
248                                         return -ENOMEM;
249
250                                 l = t;
251                         }
252
253                         assert((unsigned) r < n);
254                         l[r++] = ifindex;
255                 } else
256                         r++;
257         }
258
259         if (ifindices) {
260                 *ifindices = l;
261                 l = NULL;
262         }
263
264         return r;
265 }
266
267 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
268         return (int) (unsigned long) m - 1;
269 }
270
271 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
272         return (sd_network_monitor*) (unsigned long) (fd + 1);
273 }
274
275 _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
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
285         if (!category || streq(category, "links")) {
286                 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
287                 if (k < 0) {
288                         safe_close(fd);
289                         return -errno;
290                 }
291
292                 good = true;
293         }
294
295         if (!category || streq(category, "leases")) {
296                 k = inotify_add_watch(fd, "/run/systemd/netif/leases/", IN_MOVED_TO|IN_DELETE);
297                 if (k < 0) {
298                         safe_close(fd);
299                         return -errno;
300                 }
301
302                 good = true;
303         }
304
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 }