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 /* wait for networkd to be aware of all the links given on the commandline */
120 STRV_FOREACH(ifname, arg_interfaces) {
121 _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
125 r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, 0);
127 log_warning("could not create GETLINK message: %s", strerror(-r));
131 r = sd_rtnl_message_append_string(message, IFLA_IFNAME, *ifname);
133 log_warning("could not attach ifname to GETLINK message: %s", strerror(-r));
137 r = sd_rtnl_call(m->rtnl, message, 0, &reply);
140 log_warning("could not get link info for %s: %s", *ifname,
143 /* link does not yet exist */
147 r = sd_rtnl_message_link_get_ifindex(reply, &index);
149 log_warning("could not get ifindex: %s", strerror(-r));
154 log_warning("invalid ifindex %d for %s", index, *ifname);
158 for (i = 0; i < n; i++) {
159 if (indices[i] == (unsigned) index) {
166 /* link exists, but networkd is not yet aware of it */
171 /* wait for all links networkd manages to be in admin state 'configured'
172 and at least one link to gain a carrier */
173 for (i = 0; i < n; i++) {
174 _cleanup_free_ char *state = NULL, *oper_state = NULL;
176 if (sd_network_link_is_loopback(indices[i]))
177 /* ignore loopback devices */
180 r = sd_network_get_link_state(indices[i], &state);
181 if (r == -EBUSY || (r >= 0 && !streq(state, "configured")))
182 /* not yet processed by udev, or managed by networkd, but not yet configured */
185 r = sd_network_get_link_operational_state(indices[i], &oper_state);
187 (streq(oper_state, "degraded") ||
188 streq(oper_state, "routable")))
189 /* we wait for at least one link to be ready,
190 regardless of who manages it */
197 static int monitor_event_handler(sd_event_source *s, int fd, uint32_t revents,
199 Manager *m = userdata;
204 if (all_configured(m))
205 sd_event_exit(m->event, 0);
207 sd_network_monitor_flush(m->monitor);
212 void manager_free(Manager *m) {
216 sd_event_unref(m->event);
217 sd_rtnl_unref(m->rtnl);
222 int main(int argc, char *argv[]) {
223 _cleanup_manager_free_ Manager *m = NULL;
224 _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
229 log_parse_environment();
232 r = parse_argv(argc, argv);
237 log_set_max_level(LOG_WARNING);
239 m = new0(Manager, 1);
243 r = sd_event_new(&m->event);
245 log_error("Could not create event: %s", strerror(-r));
249 r = sd_rtnl_open(&m->rtnl, 0);
251 log_error("Could not create rtnl: %s", strerror(-r));
255 r = sd_network_monitor_new(NULL, &m->monitor);
257 log_error("Could not create monitor: %s", strerror(-r));
261 fd = sd_network_monitor_get_fd(m->monitor);
263 log_error("Could not get monitor fd: %s", strerror(-r));
267 events = sd_network_monitor_get_events(m->monitor);
269 log_error("Could not get monitor events: %s", strerror(-r));
273 r = sd_event_add_io(m->event, &event_source, fd, events, &monitor_event_handler,
276 log_error("Could not add io event source: %s", strerror(-r));
280 if (all_configured(m)) {
287 "STATUS=Waiting for network connections...");
289 r = sd_event_loop(m->event);
291 log_error("Event loop failed: %s", strerror(-r));
297 "STATUS=All interfaces configured...");
299 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;