]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/sd-network.c
sd-network: add new library
[thirdparty/systemd.git] / src / network / sd-network.c
CommitLineData
fe8db0c5
TG
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
154static inline int MONITOR_TO_FD(sd_network_monitor *m) {
155 return (int) (unsigned long) m - 1;
156}
157
158static 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}