chiark / gitweb /
sd-network: turn states 'unknown' and 'unmanaged' into errnos
[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, "netif")) {
170                 k = inotify_add_watch(fd, "/run/systemd/network/links/", IN_MOVED_TO|IN_DELETE);
171                 if (k < 0) {
172                         close_nointr_nofail(fd);
173                         return -errno;
174                 }
175
176                 good = true;
177         }
178
179         if (!good) {
180                 close_nointr(fd);
181                 return -EINVAL;
182         }
183
184         *m = FD_TO_MONITOR(fd);
185         return 0;
186 }
187
188 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
189         int fd;
190
191         assert_return(m, NULL);
192
193         fd = MONITOR_TO_FD(m);
194         close_nointr(fd);
195
196         return NULL;
197 }
198
199 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
200
201         assert_return(m, -EINVAL);
202
203         return flush_fd(MONITOR_TO_FD(m));
204 }
205
206 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
207
208         assert_return(m, -EINVAL);
209
210         return MONITOR_TO_FD(m);
211 }
212
213 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
214
215         assert_return(m, -EINVAL);
216
217         /* For now we will only return POLLIN here, since we don't
218          * need anything else ever for inotify.  However, let's have
219          * this API to keep our options open should we later on need
220          * it. */
221         return POLLIN;
222 }
223
224 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
225
226         assert_return(m, -EINVAL);
227         assert_return(timeout_usec, -EINVAL);
228
229         /* For now we will only return (uint64_t) -1, since we don't
230          * need any timeout. However, let's have this API to keep our
231          * options open should we later on need it. */
232         *timeout_usec = (uint64_t) -1;
233         return 0;
234 }