chiark / gitweb /
networkd: manager - refactor link tracking a bit
[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 "dhcp-lease-internal.h"
36
37 static int link_get_flags(unsigned index, unsigned *flags) {
38         _cleanup_free_ char *s = NULL, *p = NULL;
39         int r;
40
41         assert(index);
42         assert(flags);
43
44         if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
45                 return -ENOMEM;
46
47         r = parse_env_file(p, NEWLINE, "FLAGS", &s, NULL);
48         if (r == -ENOENT)
49                 return -ENODATA;
50         else if (r < 0)
51                 return r;
52         else if (!s)
53                 return -EIO;
54
55         return safe_atou(s, flags);
56 }
57
58 _public_ int sd_network_link_is_loopback(unsigned index) {
59         unsigned flags;
60         int r;
61
62         r = link_get_flags(index, &flags);
63         if (r < 0)
64                 return 0;
65
66         return flags & IFF_LOOPBACK;
67 }
68
69 _public_ int sd_network_get_link_state(unsigned index, char **state) {
70         _cleanup_free_ char *s = NULL, *p = NULL;
71         int r;
72
73         assert_return(index, -EINVAL);
74         assert_return(state, -EINVAL);
75
76         if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
77                 return -ENOMEM;
78
79         r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
80         if (r == -ENOENT)
81                 return -ENODATA;
82         else if (r < 0)
83                 return r;
84         else if (!s)
85                 return -EIO;
86
87         if (streq(s, "unmanaged"))
88                 return -EUNATCH;
89         else if (streq(s, "initializing"))
90                 return -EBUSY;
91
92         *state = s;
93         s = NULL;
94
95         return 0;
96 }
97
98 _public_ int sd_network_get_operational_state(char **state) {
99         _cleanup_free_ char *s = NULL;
100         int r;
101
102         assert_return(state, -EINVAL);
103
104         r = parse_env_file("/run/systemd/network/state", NEWLINE, "OPER_STATE",
105                            &s, NULL);
106         if (r == -ENOENT)
107                 return -ENODATA;
108         else if (r < 0)
109                 return r;
110         else if (!s)
111                 return -EIO;
112
113         *state = s;
114         s = NULL;
115
116         return 0;
117 }
118
119 _public_ int sd_network_get_link_operational_state(unsigned index, char **state) {
120         _cleanup_free_ char *s = NULL, *p = NULL;
121         int r;
122
123         assert_return(index, -EINVAL);
124         assert_return(state, -EINVAL);
125
126         if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
127                 return -ENOMEM;
128
129         r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
130         if (r == -ENOENT)
131                 return -ENODATA;
132         else if (r < 0)
133                 return r;
134         else if (!s)
135                 return -EIO;
136
137         *state = s;
138         s = NULL;
139
140         return 0;
141 }
142
143 _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
144         sd_dhcp_lease *lease;
145         char *p, *s = NULL;
146         int r;
147
148         assert_return(index, -EINVAL);
149         assert_return(ret, -EINVAL);
150
151         if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
152                 return -ENOMEM;
153
154         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
155         free(p);
156
157         if (r < 0) {
158                 free(s);
159                 return r;
160         } else if (!s)
161                 return -EIO;
162
163         r = dhcp_lease_load(s, &lease);
164         if (r < 0)
165                 return r;
166
167         *ret = lease;
168
169         return 0;
170 }
171
172 _public_ int sd_network_get_ifindices(unsigned **indices) {
173         _cleanup_closedir_ DIR *d;
174         int r = 0;
175         unsigned n = 0;
176         _cleanup_free_ uid_t *l = NULL;
177
178         d = opendir("/run/systemd/network/links/");
179         if (!d)
180                 return -errno;
181
182         for (;;) {
183                 struct dirent *de;
184                 int k;
185                 unsigned index;
186
187                 errno = 0;
188                 de = readdir(d);
189                 if (!de && errno != 0)
190                         return -errno;
191
192                 if (!de)
193                         break;
194
195                 dirent_ensure_type(d, de);
196
197                 if (!dirent_is_file(de))
198                         continue;
199
200                 k = safe_atou(de->d_name, &index);
201                 if (k < 0)
202                         continue;
203
204                 if (indices) {
205                         if ((unsigned) r >= n) {
206                                 unsigned *t;
207
208                                 n = MAX(16, 2*r);
209                                 t = realloc(l, sizeof(unsigned) * n);
210                                 if (!t)
211                                         return -ENOMEM;
212
213                                 l = t;
214                         }
215
216                         assert((unsigned) r < n);
217                         l[r++] = index;
218                 } else
219                         r++;
220         }
221
222         if (indices) {
223                 *indices = l;
224                 l = NULL;
225         }
226
227         return r;
228 }
229
230 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
231         return (int) (unsigned long) m - 1;
232 }
233
234 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
235         return (sd_network_monitor*) (unsigned long) (fd + 1);
236 }
237
238 _public_ int sd_network_monitor_new(const char *category, sd_network_monitor **m) {
239         int fd, k;
240         bool good = false;
241
242         assert_return(m, -EINVAL);
243
244         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
245         if (fd < 0)
246                 return -errno;
247
248         if (!category || streq(category, "links")) {
249                 k = inotify_add_watch(fd, "/run/systemd/network/links/", IN_MOVED_TO|IN_DELETE);
250                 if (k < 0) {
251                         safe_close(fd);
252                         return -errno;
253                 }
254
255                 good = true;
256         }
257
258         if (!category || streq(category, "leases")) {
259                 k = inotify_add_watch(fd, "/run/systemd/network/leases/", IN_MOVED_TO|IN_DELETE);
260                 if (k < 0) {
261                         safe_close(fd);
262                         return -errno;
263                 }
264
265                 good = true;
266         }
267
268         if (!good) {
269                 close_nointr(fd);
270                 return -EINVAL;
271         }
272
273         *m = FD_TO_MONITOR(fd);
274         return 0;
275 }
276
277 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
278         int fd;
279
280         assert_return(m, NULL);
281
282         fd = MONITOR_TO_FD(m);
283         close_nointr(fd);
284
285         return NULL;
286 }
287
288 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
289
290         assert_return(m, -EINVAL);
291
292         return flush_fd(MONITOR_TO_FD(m));
293 }
294
295 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
296
297         assert_return(m, -EINVAL);
298
299         return MONITOR_TO_FD(m);
300 }
301
302 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
303
304         assert_return(m, -EINVAL);
305
306         /* For now we will only return POLLIN here, since we don't
307          * need anything else ever for inotify.  However, let's have
308          * this API to keep our options open should we later on need
309          * it. */
310         return POLLIN;
311 }
312
313 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
314
315         assert_return(m, -EINVAL);
316         assert_return(timeout_usec, -EINVAL);
317
318         /* For now we will only return (uint64_t) -1, since we don't
319          * need any timeout. However, let's have this API to keep our
320          * options open should we later on need it. */
321         *timeout_usec = (uint64_t) -1;
322         return 0;
323 }