1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <getopt.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 
7 #include "sd-daemon.h"
8 
9 #include "daemon-util.h"
10 #include "main-func.h"
11 #include "manager.h"
12 #include "pretty-print.h"
13 #include "signal-util.h"
14 #include "socket-util.h"
15 #include "strv.h"
16 
17 static bool arg_quiet = false;
18 static usec_t arg_timeout = 120 * USEC_PER_SEC;
19 static Hashmap *arg_interfaces = NULL;
20 static char **arg_ignore = NULL;
21 static LinkOperationalStateRange arg_required_operstate = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID };
22 static AddressFamily arg_required_family = ADDRESS_FAMILY_NO;
23 static bool arg_any = false;
24 
25 STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_freep);
26 STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep);
27 
help(void)28 static int help(void) {
29         _cleanup_free_ char *link = NULL;
30         int r;
31 
32         r = terminal_urlify_man("systemd-networkd-wait-online.service", "8", &link);
33         if (r < 0)
34                 return log_oom();
35 
36         printf("%s [OPTIONS...]\n\n"
37                "Block until network is configured.\n\n"
38                "  -h --help                 Show this help\n"
39                "     --version              Print version string\n"
40                "  -q --quiet                Do not show status information\n"
41                "  -i --interface=INTERFACE[:MIN_OPERSTATE[:MAX_OPERSTATE]]\n"
42                "                            Block until at least these interfaces have appeared\n"
43                "     --ignore=INTERFACE     Don't take these interfaces into account\n"
44                "  -o --operational-state=MIN_OPERSTATE[:MAX_OPERSTATE]\n"
45                "                            Required operational state\n"
46                "  -4 --ipv4                 Requires at least one IPv4 address\n"
47                "  -6 --ipv6                 Requires at least one IPv6 address\n"
48                "     --any                  Wait until at least one of the interfaces is online\n"
49                "     --timeout=SECS         Maximum time to wait for network connectivity\n"
50                "\nSee the %s for details.\n",
51                program_invocation_short_name,
52                link);
53 
54         return 0;
55 }
56 
parse_interface_with_operstate_range(const char * str)57 static int parse_interface_with_operstate_range(const char *str) {
58         _cleanup_free_ char *ifname = NULL;
59         _cleanup_free_ LinkOperationalStateRange *range = NULL;
60         const char *p;
61         int r;
62 
63         assert(str);
64 
65         range = new(LinkOperationalStateRange, 1);
66         if (!range)
67                 return log_oom();
68 
69         p = strchr(str, ':');
70         if (p) {
71                 r = parse_operational_state_range(p + 1, range);
72                 if (r < 0)
73                          log_error_errno(r, "Invalid operational state range '%s'", p + 1);
74 
75                 ifname = strndup(optarg, p - optarg);
76         } else {
77                 range->min = _LINK_OPERSTATE_INVALID;
78                 range->max = _LINK_OPERSTATE_INVALID;
79                 ifname = strdup(str);
80         }
81         if (!ifname)
82                 return log_oom();
83 
84         if (!ifname_valid(ifname))
85                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
86                                        "Invalid interface name '%s'", ifname);
87 
88         r = hashmap_ensure_put(&arg_interfaces, &string_hash_ops, ifname, TAKE_PTR(range));
89         if (r == -ENOMEM)
90                 return log_oom();
91         if (r < 0)
92                 return log_error_errno(r, "Failed to store interface name: %m");
93         if (r == 0)
94                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
95                                        "Interface name %s is already specified", ifname);
96 
97         TAKE_PTR(ifname);
98         return 0;
99 }
100 
parse_argv(int argc,char * argv[])101 static int parse_argv(int argc, char *argv[]) {
102 
103         enum {
104                 ARG_VERSION = 0x100,
105                 ARG_IGNORE,
106                 ARG_ANY,
107                 ARG_TIMEOUT,
108         };
109 
110         static const struct option options[] = {
111                 { "help",              no_argument,       NULL, 'h'         },
112                 { "version",           no_argument,       NULL, ARG_VERSION },
113                 { "quiet",             no_argument,       NULL, 'q'         },
114                 { "interface",         required_argument, NULL, 'i'         },
115                 { "ignore",            required_argument, NULL, ARG_IGNORE  },
116                 { "operational-state", required_argument, NULL, 'o'         },
117                 { "ipv4",              no_argument,       NULL, '4'         },
118                 { "ipv6",              no_argument,       NULL, '6'         },
119                 { "any",               no_argument,       NULL, ARG_ANY     },
120                 { "timeout",           required_argument, NULL, ARG_TIMEOUT },
121                 {}
122         };
123 
124         int c, r;
125 
126         assert(argc >= 0);
127         assert(argv);
128 
129         while ((c = getopt_long(argc, argv, "hi:qo:46", options, NULL)) >= 0)
130 
131                 switch (c) {
132 
133                 case 'h':
134                         help();
135                         return 0;
136 
137                 case 'q':
138                         arg_quiet = true;
139                         break;
140 
141                 case ARG_VERSION:
142                         return version();
143 
144                 case 'i':
145                         r = parse_interface_with_operstate_range(optarg);
146                         if (r < 0)
147                                 return r;
148                         break;
149 
150                 case ARG_IGNORE:
151                         if (strv_extend(&arg_ignore, optarg) < 0)
152                                 return log_oom();
153 
154                         break;
155 
156                 case 'o': {
157                         LinkOperationalStateRange range;
158 
159                         r = parse_operational_state_range(optarg, &range);
160                         if (r < 0)
161                                 return log_error_errno(r, "Invalid operational state range '%s'", optarg);
162 
163                         arg_required_operstate = range;
164 
165                         break;
166                 }
167 
168                 case '4':
169                         arg_required_family |= ADDRESS_FAMILY_IPV4;
170                         break;
171 
172                 case '6':
173                         arg_required_family |= ADDRESS_FAMILY_IPV6;
174                         break;
175 
176                 case ARG_ANY:
177                         arg_any = true;
178                         break;
179 
180                 case ARG_TIMEOUT:
181                         r = parse_sec(optarg, &arg_timeout);
182                         if (r < 0)
183                                 return r;
184                         break;
185 
186                 case '?':
187                         return -EINVAL;
188 
189                 default:
190                         assert_not_reached();
191                 }
192 
193         return 1;
194 }
195 
run(int argc,char * argv[])196 static int run(int argc, char *argv[]) {
197         _cleanup_(manager_freep) Manager *m = NULL;
198         _unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
199         int r;
200 
201         log_setup();
202 
203         umask(0022);
204 
205         r = parse_argv(argc, argv);
206         if (r <= 0)
207                 return r;
208 
209         if (arg_quiet)
210                 log_set_max_level(LOG_ERR);
211 
212         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
213 
214         r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_required_family, arg_any, arg_timeout);
215         if (r < 0)
216                 return log_error_errno(r, "Could not create manager: %m");
217 
218         if (manager_configured(m))
219                 goto success;
220 
221         notify_message = notify_start("READY=1\n"
222                                       "STATUS=Waiting for network connections...",
223                                       "STATUS=Failed to wait for network connectivity...");
224 
225         r = sd_event_loop(m->event);
226         if (r == -ETIMEDOUT)
227                 return log_error_errno(r, "Timeout occurred while waiting for network connectivity.");
228         if (r < 0)
229                 return log_error_errno(r, "Event loop failed: %m");
230 
231 success:
232         notify_message = "STATUS=All interfaces configured...";
233 
234         return 0;
235 }
236 
237 DEFINE_MAIN_FUNCTION(run);
238