chiark / gitweb /
c86781220957347fa4b0440737a4cd8fcbf0d02c
[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_link_operational_state(unsigned index, char **state) {
99         _cleanup_free_ char *s = NULL, *p = NULL;
100         int r;
101
102         assert_return(index, -EINVAL);
103         assert_return(state, -EINVAL);
104
105         if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
106                 return -ENOMEM;
107
108         r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
109         if (r == -ENOENT)
110                 return -ENODATA;
111         else if (r < 0)
112                 return r;
113         else if (!s)
114                 return -EIO;
115
116         *state = s;
117         s = NULL;
118
119         return 0;
120 }
121
122 _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
123         sd_dhcp_lease *lease;
124         char *p, *s = NULL;
125         int r;
126
127         assert_return(index, -EINVAL);
128         assert_return(ret, -EINVAL);
129
130         if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
131                 return -ENOMEM;
132
133         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
134         free(p);
135
136         if (r < 0) {
137                 free(s);
138                 return r;
139         } else if (!s)
140                 return -EIO;
141
142         r = dhcp_lease_load(s, &lease);
143         if (r < 0)
144                 return r;
145
146         *ret = lease;
147
148         return 0;
149 }
150
151 _public_ int sd_network_get_ifindices(unsigned **indices) {
152         _cleanup_closedir_ DIR *d;
153         int r = 0;
154         unsigned n = 0;
155         _cleanup_free_ uid_t *l = NULL;
156
157         d = opendir("/run/systemd/network/links/");
158         if (!d)
159                 return -errno;
160
161         for (;;) {
162                 struct dirent *de;
163                 int k;
164                 unsigned index;
165
166                 errno = 0;
167                 de = readdir(d);
168                 if (!de && errno != 0)
169                         return -errno;
170
171                 if (!de)
172                         break;
173
174                 dirent_ensure_type(d, de);
175
176                 if (!dirent_is_file(de))
177                         continue;
178
179                 k = safe_atou(de->d_name, &index);
180                 if (k < 0)
181                         continue;
182
183                 if (indices) {
184                         if ((unsigned) r >= n) {
185                                 unsigned *t;
186
187                                 n = MAX(16, 2*r);
188                                 t = realloc(l, sizeof(unsigned) * n);
189                                 if (!t)
190                                         return -ENOMEM;
191
192                                 l = t;
193                         }
194
195                         assert((unsigned) r < n);
196                         l[r++] = index;
197                 } else
198                         r++;
199         }
200
201         if (indices) {
202                 *indices = l;
203                 l = NULL;
204         }
205
206         return r;
207 }
208
209 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
210         return (int) (unsigned long) m - 1;
211 }
212
213 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
214         return (sd_network_monitor*) (unsigned long) (fd + 1);
215 }
216
217 _public_ int sd_network_monitor_new(const char *category, sd_network_monitor **m) {
218         int fd, k;
219         bool good = false;
220
221         assert_return(m, -EINVAL);
222
223         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
224         if (fd < 0)
225                 return -errno;
226
227         if (!category || streq(category, "links")) {
228                 k = inotify_add_watch(fd, "/run/systemd/network/links/", IN_MOVED_TO|IN_DELETE);
229                 if (k < 0) {
230                         safe_close(fd);
231                         return -errno;
232                 }
233
234                 good = true;
235         }
236
237         if (!category || streq(category, "leases")) {
238                 k = inotify_add_watch(fd, "/run/systemd/network/leases/", IN_MOVED_TO|IN_DELETE);
239                 if (k < 0) {
240                         safe_close(fd);
241                         return -errno;
242                 }
243
244                 good = true;
245         }
246
247         if (!good) {
248                 close_nointr(fd);
249                 return -EINVAL;
250         }
251
252         *m = FD_TO_MONITOR(fd);
253         return 0;
254 }
255
256 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
257         int fd;
258
259         assert_return(m, NULL);
260
261         fd = MONITOR_TO_FD(m);
262         close_nointr(fd);
263
264         return NULL;
265 }
266
267 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
268
269         assert_return(m, -EINVAL);
270
271         return flush_fd(MONITOR_TO_FD(m));
272 }
273
274 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
275
276         assert_return(m, -EINVAL);
277
278         return MONITOR_TO_FD(m);
279 }
280
281 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
282
283         assert_return(m, -EINVAL);
284
285         /* For now we will only return POLLIN here, since we don't
286          * need anything else ever for inotify.  However, let's have
287          * this API to keep our options open should we later on need
288          * it. */
289         return POLLIN;
290 }
291
292 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
293
294         assert_return(m, -EINVAL);
295         assert_return(timeout_usec, -EINVAL);
296
297         /* For now we will only return (uint64_t) -1, since we don't
298          * need any timeout. However, let's have this API to keep our
299          * options open should we later on need it. */
300         *timeout_usec = (uint64_t) -1;
301         return 0;
302 }