chiark / gitweb /
sd-event: make it easy to bind signal handling to event loop exits
[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
29 #include "util.h"
30 #include "macro.h"
31 #include "strv.h"
32 #include "fileio.h"
33 #include "sd-network.h"
34 #include "dhcp-lease-internal.h"
35
36 _public_ int sd_network_get_link_state(unsigned index, char **state) {
37         _cleanup_free_ char *s = NULL, *p = NULL;
38         int r;
39
40         assert_return(index, -EINVAL);
41         assert_return(state, -EINVAL);
42
43         if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
44                 return -ENOMEM;
45
46         r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
47
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, "unmanaged"))
56                 return -EUNATCH;
57
58         *state = s;
59         s = NULL;
60
61         return 0;
62 }
63
64 _public_ int sd_network_get_dhcp_lease(unsigned index, sd_dhcp_lease **ret) {
65         sd_dhcp_lease *lease;
66         char *p, *s = NULL;
67         int r;
68
69         assert_return(index, -EINVAL);
70         assert_return(ret, -EINVAL);
71
72         if (asprintf(&p, "/run/systemd/network/links/%u", index) < 0)
73                 return -ENOMEM;
74
75         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
76         free(p);
77
78         if (r < 0) {
79                 free(s);
80                 return r;
81         } else if (!s)
82                 return -EIO;
83
84         r = dhcp_lease_load(s, &lease);
85         if (r < 0)
86                 return r;
87
88         *ret = lease;
89
90         return 0;
91 }
92
93 _public_ int sd_network_get_ifindices(unsigned **indices) {
94         _cleanup_closedir_ DIR *d;
95         int r = 0;
96         unsigned n = 0;
97         _cleanup_free_ uid_t *l = NULL;
98
99         d = opendir("/run/systemd/network/links/");
100         if (!d)
101                 return -errno;
102
103         for (;;) {
104                 struct dirent *de;
105                 int k;
106                 unsigned index;
107
108                 errno = 0;
109                 de = readdir(d);
110                 if (!de && errno != 0)
111                         return -errno;
112
113                 if (!de)
114                         break;
115
116                 dirent_ensure_type(d, de);
117
118                 if (!dirent_is_file(de))
119                         continue;
120
121                 k = safe_atou(de->d_name, &index);
122                 if (k < 0)
123                         continue;
124
125                 if (indices) {
126                         if ((unsigned) r >= n) {
127                                 unsigned *t;
128
129                                 n = MAX(16, 2*r);
130                                 t = realloc(l, sizeof(unsigned) * n);
131                                 if (!t)
132                                         return -ENOMEM;
133
134                                 l = t;
135                         }
136
137                         assert((unsigned) r < n);
138                         l[r++] = index;
139                 } else
140                         r++;
141         }
142
143         if (indices) {
144                 *indices = l;
145                 l = NULL;
146         }
147
148         return r;
149 }
150
151 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
152         return (int) (unsigned long) m - 1;
153 }
154
155 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
156         return (sd_network_monitor*) (unsigned long) (fd + 1);
157 }
158
159 _public_ int sd_network_monitor_new(const char *category, sd_network_monitor **m) {
160         int fd, k;
161         bool good = false;
162
163         assert_return(m, -EINVAL);
164
165         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
166         if (fd < 0)
167                 return -errno;
168
169         if (!category || streq(category, "links")) {
170                 k = inotify_add_watch(fd, "/run/systemd/network/links/", IN_MOVED_TO|IN_DELETE);
171                 if (k < 0) {
172                         safe_close(fd);
173                         return -errno;
174                 }
175
176                 good = true;
177         }
178
179         if (!category || streq(category, "leases")) {
180                 k = inotify_add_watch(fd, "/run/systemd/network/leases/", IN_MOVED_TO|IN_DELETE);
181                 if (k < 0) {
182                         safe_close(fd);
183                         return -errno;
184                 }
185
186                 good = true;
187         }
188
189         if (!good) {
190                 close_nointr(fd);
191                 return -EINVAL;
192         }
193
194         *m = FD_TO_MONITOR(fd);
195         return 0;
196 }
197
198 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
199         int fd;
200
201         assert_return(m, NULL);
202
203         fd = MONITOR_TO_FD(m);
204         close_nointr(fd);
205
206         return NULL;
207 }
208
209 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
210
211         assert_return(m, -EINVAL);
212
213         return flush_fd(MONITOR_TO_FD(m));
214 }
215
216 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
217
218         assert_return(m, -EINVAL);
219
220         return MONITOR_TO_FD(m);
221 }
222
223 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
224
225         assert_return(m, -EINVAL);
226
227         /* For now we will only return POLLIN here, since we don't
228          * need anything else ever for inotify.  However, let's have
229          * this API to keep our options open should we later on need
230          * it. */
231         return POLLIN;
232 }
233
234 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
235
236         assert_return(m, -EINVAL);
237         assert_return(timeout_usec, -EINVAL);
238
239         /* For now we will only return (uint64_t) -1, since we don't
240          * need any timeout. However, let's have this API to keep our
241          * options open should we later on need it. */
242         *timeout_usec = (uint64_t) -1;
243         return 0;
244 }