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