]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-network/sd-network.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / libsystemd / sd-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 <errno.h>
24 #include <poll.h>
25 #include <string.h>
26 #include <sys/inotify.h>
27
28 #include "sd-network.h"
29
30 #include "fileio.h"
31 #include "macro.h"
32 #include "string-util.h"
33 #include "strv.h"
34 #include "util.h"
35
36 _public_ int sd_network_get_operational_state(char **state) {
37 _cleanup_free_ char *s = NULL;
38 int r;
39
40 assert_return(state, -EINVAL);
41
42 r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE", &s, NULL);
43 if (r == -ENOENT)
44 return -ENODATA;
45 if (r < 0)
46 return r;
47 if (isempty(s))
48 return -ENODATA;
49
50 *state = s;
51 s = NULL;
52
53 return 0;
54 }
55
56 static int network_get_strv(const char *key, char ***ret) {
57 _cleanup_strv_free_ char **a = NULL;
58 _cleanup_free_ char *s = NULL;
59 int r;
60
61 assert_return(ret, -EINVAL);
62
63 r = parse_env_file("/run/systemd/netif/state", NEWLINE, key, &s, NULL);
64 if (r == -ENOENT)
65 return -ENODATA;
66 if (r < 0)
67 return r;
68 if (isempty(s)) {
69 *ret = NULL;
70 return 0;
71 }
72
73 a = strv_split(s, " ");
74 if (!a)
75 return -ENOMEM;
76
77 strv_uniq(a);
78 r = strv_length(a);
79
80 *ret = a;
81 a = NULL;
82
83 return r;
84 }
85
86 _public_ int sd_network_get_dns(char ***ret) {
87 return network_get_strv("DNS", ret);
88 }
89
90 _public_ int sd_network_get_ntp(char ***ret) {
91 return network_get_strv("NTP", ret);
92 }
93
94 _public_ int sd_network_get_domains(char ***ret) {
95 return network_get_strv("DOMAINS", ret);
96 }
97
98 _public_ int sd_network_link_get_setup_state(int ifindex, char **state) {
99 _cleanup_free_ char *s = NULL, *p = NULL;
100 int r;
101
102 assert_return(ifindex > 0, -EINVAL);
103 assert_return(state, -EINVAL);
104
105 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
106 return -ENOMEM;
107
108 r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
109 if (r == -ENOENT)
110 return -ENODATA;
111 if (r < 0)
112 return r;
113 if (isempty(s))
114 return -ENODATA;
115
116 *state = s;
117 s = NULL;
118
119 return 0;
120 }
121
122 _public_ int sd_network_link_get_network_file(int ifindex, char **filename) {
123 _cleanup_free_ char *s = NULL, *p = NULL;
124 int r;
125
126 assert_return(ifindex > 0, -EINVAL);
127 assert_return(filename, -EINVAL);
128
129 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
130 return -ENOMEM;
131
132 r = parse_env_file(p, NEWLINE, "NETWORK_FILE", &s, NULL);
133 if (r == -ENOENT)
134 return -ENODATA;
135 if (r < 0)
136 return r;
137 if (isempty(s))
138 return -ENODATA;
139
140 *filename = s;
141 s = NULL;
142
143 return 0;
144 }
145
146 _public_ int sd_network_link_get_operational_state(int ifindex, char **state) {
147 _cleanup_free_ char *s = NULL, *p = NULL;
148 int r;
149
150 assert_return(ifindex > 0, -EINVAL);
151 assert_return(state, -EINVAL);
152
153 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
154 return -ENOMEM;
155
156 r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
157 if (r == -ENOENT)
158 return -ENODATA;
159 if (r < 0)
160 return r;
161 if (isempty(s))
162 return -ENODATA;
163
164 *state = s;
165 s = NULL;
166
167 return 0;
168 }
169
170 _public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
171 _cleanup_free_ char *s = NULL, *p = NULL;
172 int r;
173
174 assert_return(ifindex > 0, -EINVAL);
175 assert_return(llmnr, -EINVAL);
176
177 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
178 return -ENOMEM;
179
180 r = parse_env_file(p, NEWLINE, "LLMNR", &s, NULL);
181 if (r == -ENOENT)
182 return -ENODATA;
183 if (r < 0)
184 return r;
185 if (isempty(s))
186 return -ENODATA;
187
188 *llmnr = s;
189 s = NULL;
190
191 return 0;
192 }
193
194 _public_ int sd_network_link_get_lldp(int ifindex, char **lldp) {
195 _cleanup_free_ char *s = NULL, *p = NULL;
196 size_t size;
197 int r;
198
199 assert_return(ifindex > 0, -EINVAL);
200 assert_return(lldp, -EINVAL);
201
202 if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0)
203 return -ENOMEM;
204
205 r = read_full_file(p, &s, &size);
206 if (r == -ENOENT)
207 return -ENODATA;
208 if (r < 0)
209 return r;
210 if (size <= 0)
211 return -ENODATA;
212
213 *lldp = s;
214 s = NULL;
215
216 return 0;
217 }
218
219 int sd_network_link_get_timezone(int ifindex, char **ret) {
220 _cleanup_free_ char *s = NULL, *p = NULL;
221 int r;
222
223 assert_return(ifindex > 0, -EINVAL);
224 assert_return(ret, -EINVAL);
225
226 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
227 return -ENOMEM;
228
229 r = parse_env_file(p, NEWLINE, "TIMEZONE", &s, NULL);
230 if (r == -ENOENT)
231 return -ENODATA;
232 if (r < 0)
233 return r;
234 if (isempty(s))
235 return -ENODATA;
236
237 *ret = s;
238 s = NULL;
239 return 0;
240 }
241
242 static int network_get_link_strv(const char *key, int ifindex, char ***ret) {
243 _cleanup_free_ char *p = NULL, *s = NULL;
244 _cleanup_strv_free_ char **a = NULL;
245 int r;
246
247 assert_return(ifindex > 0, -EINVAL);
248 assert_return(ret, -EINVAL);
249
250 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
251 return -ENOMEM;
252
253 r = parse_env_file(p, NEWLINE, key, &s, NULL);
254 if (r == -ENOENT)
255 return -ENODATA;
256 if (r < 0)
257 return r;
258 if (isempty(s)) {
259 *ret = NULL;
260 return 0;
261 }
262
263 a = strv_split(s, " ");
264 if (!a)
265 return -ENOMEM;
266
267 strv_uniq(a);
268 r = strv_length(a);
269
270 *ret = a;
271 a = NULL;
272
273 return r;
274 }
275
276 _public_ int sd_network_link_get_dns(int ifindex, char ***ret) {
277 return network_get_link_strv("DNS", ifindex, ret);
278 }
279
280 _public_ int sd_network_link_get_ntp(int ifindex, char ***ret) {
281 return network_get_link_strv("NTP", ifindex, ret);
282 }
283
284 _public_ int sd_network_link_get_domains(int ifindex, char ***ret) {
285 return network_get_link_strv("DOMAINS", ifindex, ret);
286 }
287
288 _public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) {
289 return network_get_link_strv("CARRIER_BOUND_TO", ifindex, ret);
290 }
291
292 _public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) {
293 return network_get_link_strv("CARRIER_BOUND_BY", ifindex, ret);
294 }
295
296 _public_ int sd_network_link_get_wildcard_domain(int ifindex) {
297 int r;
298 _cleanup_free_ char *p = NULL, *s = NULL;
299
300 assert_return(ifindex > 0, -EINVAL);
301
302 if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
303 return -ENOMEM;
304
305 r = parse_env_file(p, NEWLINE, "WILDCARD_DOMAIN", &s, NULL);
306 if (r == -ENOENT)
307 return -ENODATA;
308 if (r < 0)
309 return r;
310 if (isempty(s))
311 return -ENODATA;
312
313 return parse_boolean(s);
314 }
315
316 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
317 return (int) (unsigned long) m - 1;
318 }
319
320 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
321 return (sd_network_monitor*) (unsigned long) (fd + 1);
322 }
323
324 static int monitor_add_inotify_watch(int fd) {
325 int k;
326
327 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
328 if (k >= 0)
329 return 0;
330 else if (errno != ENOENT)
331 return -errno;
332
333 k = inotify_add_watch(fd, "/run/systemd/netif/", IN_CREATE|IN_ISDIR);
334 if (k >= 0)
335 return 0;
336 else if (errno != ENOENT)
337 return -errno;
338
339 k = inotify_add_watch(fd, "/run/systemd/", IN_CREATE|IN_ISDIR);
340 if (k < 0)
341 return -errno;
342
343 return 0;
344 }
345
346 _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
347 _cleanup_close_ int fd = -1;
348 int k;
349 bool good = false;
350
351 assert_return(m, -EINVAL);
352
353 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
354 if (fd < 0)
355 return -errno;
356
357 if (!category || streq(category, "links")) {
358 k = monitor_add_inotify_watch(fd);
359 if (k < 0)
360 return k;
361
362 good = true;
363 }
364
365 if (!good)
366 return -EINVAL;
367
368 *m = FD_TO_MONITOR(fd);
369 fd = -1;
370
371 return 0;
372 }
373
374 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
375 int fd;
376
377 if (m) {
378 fd = MONITOR_TO_FD(m);
379 close_nointr(fd);
380 }
381
382 return NULL;
383 }
384
385 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
386 union inotify_event_buffer buffer;
387 struct inotify_event *e;
388 ssize_t l;
389 int fd, k;
390
391 assert_return(m, -EINVAL);
392
393 fd = MONITOR_TO_FD(m);
394
395 l = read(fd, &buffer, sizeof(buffer));
396 if (l < 0) {
397 if (errno == EAGAIN || errno == EINTR)
398 return 0;
399
400 return -errno;
401 }
402
403 FOREACH_INOTIFY_EVENT(e, buffer, l) {
404 if (e->mask & IN_ISDIR) {
405 k = monitor_add_inotify_watch(fd);
406 if (k < 0)
407 return k;
408
409 k = inotify_rm_watch(fd, e->wd);
410 if (k < 0)
411 return -errno;
412 }
413 }
414
415 return 0;
416 }
417
418 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
419
420 assert_return(m, -EINVAL);
421
422 return MONITOR_TO_FD(m);
423 }
424
425 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
426
427 assert_return(m, -EINVAL);
428
429 /* For now we will only return POLLIN here, since we don't
430 * need anything else ever for inotify. However, let's have
431 * this API to keep our options open should we later on need
432 * it. */
433 return POLLIN;
434 }
435
436 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
437
438 assert_return(m, -EINVAL);
439 assert_return(timeout_usec, -EINVAL);
440
441 /* For now we will only return (uint64_t) -1, since we don't
442 * need any timeout. However, let's have this API to keep our
443 * options open should we later on need it. */
444 *timeout_usec = (uint64_t) -1;
445 return 0;
446 }