chiark / gitweb /
6375788c95f2b46bb0b461277b05b196ff8c1437
[elogind.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 <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
37 _public_ int sd_network_get_link_state(int ifindex, char **state) {
38         _cleanup_free_ char *s = NULL, *p = NULL;
39         int r;
40
41         assert_return(ifindex > 0, -EINVAL);
42         assert_return(state, -EINVAL);
43
44         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
45                 return -ENOMEM;
46
47         r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &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         if (streq(s, "initializing"))
56                 return -EBUSY;
57
58         *state = s;
59         s = NULL;
60
61         return 0;
62 }
63
64 _public_ int sd_network_get_operational_state(char **state) {
65         _cleanup_free_ char *s = NULL;
66         int r;
67
68         assert_return(state, -EINVAL);
69
70         r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE",
71                            &s, NULL);
72         if (r == -ENOENT)
73                 return -ENODATA;
74         else if (r < 0)
75                 return r;
76         else if (!s)
77                 return -EIO;
78
79         *state = s;
80         s = NULL;
81
82         return 0;
83 }
84
85 _public_ int sd_network_get_link_operational_state(int ifindex, char **state) {
86         _cleanup_free_ char *s = NULL, *p = NULL;
87         int r;
88
89         assert_return(ifindex > 0, -EINVAL);
90         assert_return(state, -EINVAL);
91
92         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
93                 return -ENOMEM;
94
95         r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
96         if (r == -ENOENT)
97                 return -ENODATA;
98         else if (r < 0)
99                 return r;
100         else if (!s)
101                 return -EIO;
102
103         *state = s;
104         s = NULL;
105
106         return 0;
107 }
108
109 _public_ int sd_network_get_link_llmnr(int ifindex, char **llmnr) {
110         _cleanup_free_ char *s = NULL, *p = NULL;
111         int r;
112
113         assert_return(ifindex > 0, -EINVAL);
114         assert_return(llmnr, -EINVAL);
115
116         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
117                 return -ENOMEM;
118
119         r = parse_env_file(p, NEWLINE, "LLMNR", &s, NULL);
120         if (r == -ENOENT)
121                 return -ENODATA;
122         else if (r < 0)
123                 return r;
124         else if (!s)
125                 return -ENODATA;
126
127         *llmnr = s;
128         s = NULL;
129
130         return 0;
131 }
132
133 static int network_get_link_strv(const char *key, int ifindex, char ***ret) {
134         _cleanup_free_ char *p = NULL, *s = NULL;
135         _cleanup_strv_free_ char **a = NULL;
136         int r;
137
138         assert_return(ifindex > 0, -EINVAL);
139         assert_return(ret, -EINVAL);
140
141         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
142                 return -ENOMEM;
143
144         r = parse_env_file(p, NEWLINE, key, &s, NULL);
145         if (r < 0)
146                 return r;
147         else if (!s) {
148                 *ret = NULL;
149
150                 return 0;
151         }
152
153         a = strv_split(s, " ");
154         if (!a)
155                 return -ENOMEM;
156
157         strv_uniq(a);
158         r = strv_length(a);
159
160         *ret = a;
161         a = NULL;
162
163         return r;
164 }
165
166 _public_ int sd_network_get_link_dns(int ifindex, char ***ret) {
167         return network_get_link_strv("DNS", ifindex, ret);
168 }
169
170 _public_ int sd_network_get_link_ntp(int ifindex, char ***ret) {
171         return network_get_link_strv("NTP", ifindex, ret);
172 }
173
174 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
175         return (int) (unsigned long) m - 1;
176 }
177
178 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
179         return (sd_network_monitor*) (unsigned long) (fd + 1);
180 }
181
182 _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
183         int fd, k;
184         bool good = false;
185
186         assert_return(m, -EINVAL);
187
188         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
189         if (fd < 0)
190                 return -errno;
191
192         if (!category || streq(category, "links")) {
193                 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
194                 if (k < 0) {
195                         safe_close(fd);
196                         return -errno;
197                 }
198
199                 good = true;
200         }
201
202         if (!good) {
203                 close_nointr(fd);
204                 return -EINVAL;
205         }
206
207         *m = FD_TO_MONITOR(fd);
208         return 0;
209 }
210
211 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
212         int fd;
213
214         assert_return(m, NULL);
215
216         fd = MONITOR_TO_FD(m);
217         close_nointr(fd);
218
219         return NULL;
220 }
221
222 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
223
224         assert_return(m, -EINVAL);
225
226         return flush_fd(MONITOR_TO_FD(m));
227 }
228
229 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
230
231         assert_return(m, -EINVAL);
232
233         return MONITOR_TO_FD(m);
234 }
235
236 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
237
238         assert_return(m, -EINVAL);
239
240         /* For now we will only return POLLIN here, since we don't
241          * need anything else ever for inotify.  However, let's have
242          * this API to keep our options open should we later on need
243          * it. */
244         return POLLIN;
245 }
246
247 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
248
249         assert_return(m, -EINVAL);
250         assert_return(timeout_usec, -EINVAL);
251
252         /* For now we will only return (uint64_t) -1, since we don't
253          * need any timeout. However, let's have this API to keep our
254          * options open should we later on need it. */
255         *timeout_usec = (uint64_t) -1;
256         return 0;
257 }