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