1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <netinet/ether.h>
27 #include "event-util.h"
29 #include "rtnl-util.h"
30 #include "sd-daemon.h"
31 #include "sd-network.h"
32 #include "network-util.h"
33 #include "network-internal.h"
34 #include "networkd-wait-online.h"
36 #include "conf-parser.h"
41 static bool arg_quiet = false;
42 static char **arg_interfaces = NULL;
44 static int help(void) {
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);
57 static int parse_argv(int argc, char *argv[]) {
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' },
76 while ((c = getopt_long(argc, argv, "+hq", options, NULL)) >= 0) {
89 puts(SYSTEMD_FEATURES);
93 if (strv_extend(&arg_interfaces, optarg) < 0)
102 assert_not_reached("Unhandled option");
109 static bool all_configured(Manager *m) {
110 _cleanup_free_ unsigned *indices = NULL;
112 bool one_ready = false;
115 n = sd_network_get_ifindices(&indices);
119 STRV_FOREACH(ifname, arg_interfaces) {
120 _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
124 r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, 0);
126 log_warning("colud not create GETLINK message: %s", strerror(-r));
130 r = sd_rtnl_message_append_string(message, IFLA_IFNAME, *ifname);
132 log_warning("could not attach ifname to GETLINK message: %s", strerror(-r));
136 r = sd_rtnl_call(m->rtnl, message, 0, &reply);
139 log_warning("could not get link info for %s: %s", *ifname,
142 /* link does not yet exist */
146 r = sd_rtnl_message_link_get_ifindex(reply, &index);
148 log_warning("could not get ifindex: %s", strerror(-r));
153 log_warning("invalid ifindex %d for %s", index, *ifname);
157 for (i = 0; i < n; i++) {
158 if (indices[i] == (unsigned) index) {
165 /* link exists, but networkd is not yet aware of it */
169 for (i = 0; i < n; i++) {
170 _cleanup_free_ char *state = NULL;
172 r = sd_network_get_link_state(indices[i], &state);
174 _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
178 r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, indices[i]);
180 log_warning("could not create GETLINK message: %s", strerror(-r));
184 r = sd_rtnl_call(m->rtnl, message, 0, &reply);
186 log_debug("could not get link %u: %s", indices[i], strerror(-r));
190 r = sd_rtnl_message_link_get_flags(reply, &flags);
192 log_warning("could not get link flags: %s", strerror(-r));
196 r = sd_rtnl_message_read_u8(reply, IFLA_OPERSTATE, &operstate);
198 log_debug("could not get link operational state: %s", strerror(-r));
199 operstate = IF_OPER_UNKNOWN;
202 if (!(flags & IFF_LOOPBACK) &&
203 link_has_carrier(flags, operstate)) {
204 /* this link is not managed by us,
205 but something else may have
206 made it ready, so don't block */
211 } else if (r < 0 || !streq(state, "configured"))
212 /* managed by networkd, but not yet configured */
215 /* we wait for at least one link to appear */
222 static int monitor_event_handler(sd_event_source *s, int fd, uint32_t revents,
224 Manager *m = userdata;
229 if (all_configured(m))
230 sd_event_exit(m->event, 0);
235 static int newlink_event_handler(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
236 Manager *m = userdata;
241 if (all_configured(m))
242 sd_event_exit(m->event, 0);
247 void manager_free(Manager *m) {
251 sd_event_unref(m->event);
252 sd_rtnl_unref(m->rtnl);
257 int main(int argc, char *argv[]) {
258 _cleanup_manager_free_ Manager *m = NULL;
259 _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
260 _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
265 log_parse_environment();
268 r = parse_argv(argc, argv);
273 log_set_max_level(LOG_WARNING);
275 m = new0(Manager, 1);
279 r = sd_network_monitor_new(NULL, &monitor);
281 log_error("Could not create monitor: %s", strerror(-r));
285 r = sd_event_new(&m->event);
287 log_error("Could not create event: %s", strerror(-r));
291 fd = sd_network_monitor_get_fd(monitor);
293 log_error("Could not get monitor fd: %s", strerror(-r));
297 events = sd_network_monitor_get_events(monitor);
299 log_error("Could not get monitor events: %s", strerror(-r));
303 r = sd_event_add_io(m->event, &event_source, fd, events, &monitor_event_handler,
306 log_error("Could not add io event source: %s", strerror(-r));
310 r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK);
312 log_error("Could not create rtnl: %s", strerror(-r));
316 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
318 log_error("Could not attach event to rtnl: %s", strerror(-r));
322 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, newlink_event_handler, m);
326 if (all_configured(m)) {
333 "STATUS=Waiting for network connections...");
335 r = sd_event_loop(m->event);
337 log_error("Event loop failed: %s", strerror(-r));
343 "STATUS=All interfaces configured...");
345 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;