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