]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-wait-online.c
sd-network: fix parameter order for sd_network_monitor_new()
[thirdparty/systemd.git] / src / network / networkd-wait-online.c
CommitLineData
020d5900
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
3a67e927
TG
22#include <netinet/ether.h>
23#include <linux/if.h>
cef8b073 24#include <getopt.h>
3a67e927 25
020d5900 26#include "sd-event.h"
e1528e08 27#include "event-util.h"
3a67e927
TG
28#include "sd-rtnl.h"
29#include "rtnl-util.h"
020d5900
TG
30#include "sd-daemon.h"
31#include "sd-network.h"
e1528e08 32#include "network-util.h"
3a67e927
TG
33#include "network-internal.h"
34#include "networkd-wait-online.h"
020d5900 35
3a67e927
TG
36#include "conf-parser.h"
37#include "strv.h"
020d5900 38#include "util.h"
cef8b073
TG
39#include "build.h"
40
41static bool arg_quiet = false;
42static char **arg_interfaces = NULL;
43
44static int help(void) {
45
46 printf("%s [OPTIONS...]\n\n"
47 "Block until network is configured.\n\n"
48 " -h --help Show this help\n"
49 " --version Print version string\n"
50 " -q --quiet Do not show status information\n"
51 " -i --interface=INTERFACE Block until at least these interfaces have appeared\n",
52 program_invocation_short_name);
53
54 return 0;
55}
56
57static int parse_argv(int argc, char *argv[]) {
58
59 enum {
60 ARG_VERSION = 0x100,
61 };
62
63 static const struct option options[] = {
64 { "help", no_argument, NULL, 'h' },
65 { "version", no_argument, NULL, ARG_VERSION },
66 { "quiet", no_argument, NULL, 'q' },
67 { "interface", required_argument, NULL, 'i' },
68 {}
69 };
70
71 int c;
72
73 assert(argc >= 0);
74 assert(argv);
75
76 while ((c = getopt_long(argc, argv, "+hq", options, NULL)) >= 0) {
77
78 switch (c) {
79
80 case 'h':
81 return help();
82
83 case 'q':
84 arg_quiet = true;
85 break;
86
87 case ARG_VERSION:
88 puts(PACKAGE_STRING);
89 puts(SYSTEMD_FEATURES);
90 return 0;
91
92 case 'i':
93 if (strv_extend(&arg_interfaces, optarg) < 0)
94 return log_oom();
95
96 break;
97
98 case '?':
99 return -EINVAL;
100
101 default:
102 assert_not_reached("Unhandled option");
103 }
104 }
105
106 return 1;
107}
020d5900 108
3a67e927 109static bool all_configured(Manager *m) {
020d5900 110 _cleanup_free_ unsigned *indices = NULL;
3a67e927 111 char **ifname;
020d5900
TG
112 bool one_ready = false;
113 int r, n, i;
114
115 n = sd_network_get_ifindices(&indices);
116 if (n <= 0)
117 return false;
118
bc634576 119 /* wait for networkd to be aware of all the links given on the commandline */
cef8b073 120 STRV_FOREACH(ifname, arg_interfaces) {
3a67e927
TG
121 _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
122 bool found = false;
123 int index;
124
125 r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, 0);
126 if (r < 0) {
865cc19a 127 log_warning("could not create GETLINK message: %s", strerror(-r));
3a67e927
TG
128 return false;
129 }
130
131 r = sd_rtnl_message_append_string(message, IFLA_IFNAME, *ifname);
132 if (r < 0) {
133 log_warning("could not attach ifname to GETLINK message: %s", strerror(-r));
134 return false;
135 }
136
137 r = sd_rtnl_call(m->rtnl, message, 0, &reply);
138 if (r < 0) {
139 if (r != -ENODEV)
140 log_warning("could not get link info for %s: %s", *ifname,
141 strerror(-r));
142
143 /* link does not yet exist */
144 return false;
145 }
146
147 r = sd_rtnl_message_link_get_ifindex(reply, &index);
148 if (r < 0) {
149 log_warning("could not get ifindex: %s", strerror(-r));
150 return false;
151 }
152
153 if (index <= 0) {
154 log_warning("invalid ifindex %d for %s", index, *ifname);
155 return false;
156 }
157
158 for (i = 0; i < n; i++) {
159 if (indices[i] == (unsigned) index) {
160 found = true;
161 break;
162 }
163 }
164
cef8b073 165 if (!found) {
3a67e927
TG
166 /* link exists, but networkd is not yet aware of it */
167 return false;
27134b2f 168 }
3a67e927
TG
169 }
170
bc634576
TG
171 /* wait for all links networkd manages to be in admin state 'configured'
172 and at least one link to gain a carrier */
020d5900 173 for (i = 0; i < n; i++) {
bc634576
TG
174 _cleanup_free_ char *state = NULL, *oper_state = NULL;
175
176 if (sd_network_link_is_loopback(indices[i]))
177 /* ignore loopback devices */
178 continue;
020d5900
TG
179
180 r = sd_network_get_link_state(indices[i], &state);
d91d3c15
TG
181 if (r == -EBUSY || (r >= 0 && !streq(state, "configured")))
182 /* not yet processed by udev, or managed by networkd, but not yet configured */
27134b2f 183 return false;
3a67e927 184
bc634576 185 r = sd_network_get_link_operational_state(indices[i], &oper_state);
473dfd7b
TG
186 if (r >= 0 &&
187 (streq(oper_state, "degraded") ||
188 streq(oper_state, "routable")))
27134b2f
TG
189 /* we wait for at least one link to be ready,
190 regardless of who manages it */
191 one_ready = true;
020d5900
TG
192 }
193
cb6fa44c 194 return one_ready;
020d5900
TG
195}
196
3a67e927 197static int monitor_event_handler(sd_event_source *s, int fd, uint32_t revents,
020d5900 198 void *userdata) {
3a67e927
TG
199 Manager *m = userdata;
200
201 assert(m);
202 assert(m->event);
203
204 if (all_configured(m))
205 sd_event_exit(m->event, 0);
206
3a9c5a32
TG
207 sd_network_monitor_flush(m->monitor);
208
3a67e927
TG
209 return 1;
210}
020d5900 211
3a67e927
TG
212void manager_free(Manager *m) {
213 if (!m)
214 return;
215
216 sd_event_unref(m->event);
217 sd_rtnl_unref(m->rtnl);
3a67e927
TG
218
219 free(m);
220}
221
020d5900 222int main(int argc, char *argv[]) {
3a67e927 223 _cleanup_manager_free_ Manager *m = NULL;
e1528e08 224 _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
020d5900
TG
225 int r, fd, events;
226
cef8b073
TG
227 umask(0022);
228
020d5900
TG
229 log_parse_environment();
230 log_open();
231
cef8b073
TG
232 r = parse_argv(argc, argv);
233 if (r <= 0)
234 return r;
020d5900 235
cef8b073
TG
236 if (arg_quiet)
237 log_set_max_level(LOG_WARNING);
020d5900 238
3a67e927
TG
239 m = new0(Manager, 1);
240 if (!m)
241 return log_oom();
242
3a9c5a32 243 r = sd_event_new(&m->event);
020d5900 244 if (r < 0) {
3a9c5a32 245 log_error("Could not create event: %s", strerror(-r));
020d5900
TG
246 goto out;
247 }
248
3a9c5a32 249 r = sd_rtnl_open(&m->rtnl, 0);
020d5900 250 if (r < 0) {
3a9c5a32 251 log_error("Could not create rtnl: %s", strerror(-r));
020d5900
TG
252 goto out;
253 }
254
0014a4ad 255 r = sd_network_monitor_new(&m->monitor, NULL);
3a9c5a32
TG
256 if (r < 0) {
257 log_error("Could not create monitor: %s", strerror(-r));
258 goto out;
259 }
260
261 fd = sd_network_monitor_get_fd(m->monitor);
020d5900
TG
262 if (fd < 0) {
263 log_error("Could not get monitor fd: %s", strerror(-r));
264 goto out;
265 }
266
3a9c5a32 267 events = sd_network_monitor_get_events(m->monitor);
020d5900
TG
268 if (events < 0) {
269 log_error("Could not get monitor events: %s", strerror(-r));
270 goto out;
271 }
272
3a67e927
TG
273 r = sd_event_add_io(m->event, &event_source, fd, events, &monitor_event_handler,
274 m);
020d5900
TG
275 if (r < 0) {
276 log_error("Could not add io event source: %s", strerror(-r));
277 goto out;
278 }
279
3a67e927 280 if (all_configured(m)) {
020d5900
TG
281 r = 0;
282 goto out;
283 }
284
285 sd_notify(false,
286 "READY=1\n"
b6b8adbf 287 "STATUS=Waiting for network connections...");
020d5900 288
3a67e927 289 r = sd_event_loop(m->event);
020d5900
TG
290 if (r < 0) {
291 log_error("Event loop failed: %s", strerror(-r));
292 goto out;
293 }
294
295out:
296 sd_notify(false,
297 "STATUS=All interfaces configured...");
298
020d5900
TG
299 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
300}