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 */
170 for (i = 0; i < n; i++) {
171 _cleanup_free_ char *state = NULL;
172 _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
176 r = sd_network_get_link_state(indices[i], &state);
177 if (r != -EUNATCH && (r < 0 || !streq(state, "configured"))) {
178 /* managed by networkd, but not yet configured */
182 r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, indices[i]);
184 log_warning("could not create GETLINK message: %s", strerror(-r));
188 r = sd_rtnl_call(m->rtnl, message, 0, &reply);
190 log_debug("could not get link %u: %s", indices[i], strerror(-r));
194 r = sd_rtnl_message_link_get_flags(reply, &flags);
196 log_warning("could not get link flags: %s", strerror(-r));
200 r = sd_rtnl_message_read_u8(reply, IFLA_OPERSTATE, &operstate);
202 log_debug("could not get link operational state: %s", strerror(-r));
203 operstate = IF_OPER_UNKNOWN;
206 if (!(flags & IFF_LOOPBACK) &&
207 link_has_carrier(flags, operstate)) {
208 /* we wait for at least one link to be ready,
209 regardless of who manages it */
217 static int monitor_event_handler(sd_event_source *s, int fd, uint32_t revents,
219 Manager *m = userdata;
224 if (all_configured(m))
225 sd_event_exit(m->event, 0);
230 static int newlink_event_handler(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
231 Manager *m = userdata;
236 if (all_configured(m))
237 sd_event_exit(m->event, 0);
242 void manager_free(Manager *m) {
246 sd_event_unref(m->event);
247 sd_rtnl_unref(m->rtnl);
252 int main(int argc, char *argv[]) {
253 _cleanup_manager_free_ Manager *m = NULL;
254 _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
255 _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
260 log_parse_environment();
263 r = parse_argv(argc, argv);
268 log_set_max_level(LOG_WARNING);
270 m = new0(Manager, 1);
274 r = sd_network_monitor_new(NULL, &monitor);
276 log_error("Could not create monitor: %s", strerror(-r));
280 r = sd_event_new(&m->event);
282 log_error("Could not create event: %s", strerror(-r));
286 fd = sd_network_monitor_get_fd(monitor);
288 log_error("Could not get monitor fd: %s", strerror(-r));
292 events = sd_network_monitor_get_events(monitor);
294 log_error("Could not get monitor events: %s", strerror(-r));
298 r = sd_event_add_io(m->event, &event_source, fd, events, &monitor_event_handler,
301 log_error("Could not add io event source: %s", strerror(-r));
305 r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK);
307 log_error("Could not create rtnl: %s", strerror(-r));
311 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
313 log_error("Could not attach event to rtnl: %s", strerror(-r));
317 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, newlink_event_handler, m);
321 if (all_configured(m)) {
328 "STATUS=Waiting for network connections...");
330 r = sd_event_loop(m->event);
332 log_error("Event loop failed: %s", strerror(-r));
338 "STATUS=All interfaces configured...");
340 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;