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>
26 #include "event-util.h"
28 #include "rtnl-util.h"
29 #include "sd-daemon.h"
30 #include "sd-network.h"
31 #include "network-util.h"
32 #include "network-internal.h"
33 #include "networkd-wait-online.h"
35 #include "conf-parser.h"
39 static bool all_configured(Manager *m) {
40 _cleanup_free_ unsigned *indices = NULL;
42 bool one_ready = false;
45 n = sd_network_get_ifindices(&indices);
49 STRV_FOREACH(ifname, m->expected_links) {
50 _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
54 r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, 0);
56 log_warning("colud not create GETLINK message: %s", strerror(-r));
60 r = sd_rtnl_message_append_string(message, IFLA_IFNAME, *ifname);
62 log_warning("could not attach ifname to GETLINK message: %s", strerror(-r));
66 r = sd_rtnl_call(m->rtnl, message, 0, &reply);
69 log_warning("could not get link info for %s: %s", *ifname,
72 /* link does not yet exist */
76 r = sd_rtnl_message_link_get_ifindex(reply, &index);
78 log_warning("could not get ifindex: %s", strerror(-r));
83 log_warning("invalid ifindex %d for %s", index, *ifname);
87 for (i = 0; i < n; i++) {
88 if (indices[i] == (unsigned) index) {
95 /* link exists, but networkd is not yet aware of it */
99 for (i = 0; i < n; i++) {
100 _cleanup_free_ char *state = NULL;
102 r = sd_network_get_link_state(indices[i], &state);
104 _cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL, *reply = NULL;
108 r = sd_rtnl_message_new_link(m->rtnl, &message, RTM_GETLINK, indices[i]);
110 log_warning("could not create GETLINK message: %s", strerror(-r));
114 r = sd_rtnl_call(m->rtnl, message, 0, &reply);
116 log_debug("could not get link %u: %s", indices[i], strerror(-r));
120 r = sd_rtnl_message_link_get_flags(reply, &flags);
122 log_warning("could not get link flags: %s", strerror(-r));
126 r = sd_rtnl_message_read_u8(reply, IFLA_OPERSTATE, &operstate);
128 log_debug("could not get link operational state: %s", strerror(-r));
129 operstate = IF_OPER_UNKNOWN;
132 if (!(flags & IFF_LOOPBACK) &&
133 link_has_carrier(flags, operstate)) {
134 /* this link is not managed by us,
135 but something else may have
136 made it ready, so don't block */
141 } else if (r < 0 || !streq(state, "configured"))
144 /* we wait for at least one link to appear */
151 static int monitor_event_handler(sd_event_source *s, int fd, uint32_t revents,
153 Manager *m = userdata;
158 if (all_configured(m))
159 sd_event_exit(m->event, 0);
164 static int newlink_event_handler(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
165 Manager *m = userdata;
170 if (all_configured(m))
171 sd_event_exit(m->event, 0);
176 static int parse_config_file(Manager *m) {
177 static const char fn[] = "/etc/systemd/networkd-wait-online.conf";
178 _cleanup_fclose_ FILE *f = NULL;
186 log_warning("Failed to open configuration file %s: %m", fn);
190 r = config_parse(NULL, fn, f, "WaitOnline\0", config_item_perf_lookup,
191 (void*) wait_online_gperf_lookup, false, false, m);
193 log_warning("Failed to parse configuration file: %s", strerror(-r));
198 void manager_free(Manager *m) {
202 sd_event_unref(m->event);
203 sd_rtnl_unref(m->rtnl);
204 strv_free(m->expected_links);
209 int main(int argc, char *argv[]) {
210 _cleanup_manager_free_ Manager *m = NULL;
211 _cleanup_event_source_unref_ sd_event_source *event_source = NULL;
212 _cleanup_network_monitor_unref_ sd_network_monitor *monitor = NULL;
215 log_set_target(LOG_TARGET_AUTO);
216 log_parse_environment();
222 log_error("This program takes no arguments.");
227 m = new0(Manager, 1);
231 r = parse_config_file(m);
235 r = sd_network_monitor_new(NULL, &monitor);
237 log_error("Could not create monitor: %s", strerror(-r));
241 r = sd_event_new(&m->event);
243 log_error("Could not create event: %s", strerror(-r));
247 fd = sd_network_monitor_get_fd(monitor);
249 log_error("Could not get monitor fd: %s", strerror(-r));
253 events = sd_network_monitor_get_events(monitor);
255 log_error("Could not get monitor events: %s", strerror(-r));
259 r = sd_event_add_io(m->event, &event_source, fd, events, &monitor_event_handler,
262 log_error("Could not add io event source: %s", strerror(-r));
266 r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK);
268 log_error("Could not create rtnl: %s", strerror(-r));
272 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
274 log_error("Could not attach event to rtnl: %s", strerror(-r));
278 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, newlink_event_handler, m);
282 if (all_configured(m)) {
289 "STATUS=Waiting for network connections...");
291 r = sd_event_loop(m->event);
293 log_error("Event loop failed: %s", strerror(-r));
299 "STATUS=All interfaces configured...");
301 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;