]>
Commit | Line | Data |
---|---|---|
a032b68d | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
60f067b4 | 2 | |
60f067b4 | 3 | #include <getopt.h> |
bb4f798a MB |
4 | #include <sys/stat.h> |
5 | #include <sys/types.h> | |
60f067b4 | 6 | |
60f067b4 | 7 | #include "sd-daemon.h" |
6300502b | 8 | |
6e866b33 MB |
9 | #include "daemon-util.h" |
10 | #include "main-func.h" | |
2897b343 | 11 | #include "manager.h" |
6e866b33 | 12 | #include "pretty-print.h" |
6300502b | 13 | #include "signal-util.h" |
bb4f798a | 14 | #include "socket-util.h" |
6300502b | 15 | #include "strv.h" |
60f067b4 JS |
16 | |
17 | static bool arg_quiet = false; | |
e735f4d4 | 18 | static usec_t arg_timeout = 120 * USEC_PER_SEC; |
bb4f798a | 19 | static Hashmap *arg_interfaces = NULL; |
e735f4d4 | 20 | static char **arg_ignore = NULL; |
46cdbd49 | 21 | static LinkOperationalStateRange arg_required_operstate = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID }; |
8b3d4ff0 | 22 | static AddressFamily arg_required_family = ADDRESS_FAMILY_NO; |
bb4f798a | 23 | static bool arg_any = false; |
60f067b4 | 24 | |
46cdbd49 | 25 | STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_freep); |
6e866b33 MB |
26 | STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep); |
27 | ||
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 | ||
60f067b4 JS |
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" | |
46cdbd49 | 41 | " -i --interface=INTERFACE[:MIN_OPERSTATE[:MAX_OPERSTATE]]\n" |
bb4f798a | 42 | " Block until at least these interfaces have appeared\n" |
e735f4d4 | 43 | " --ignore=INTERFACE Don't take these interfaces into account\n" |
46cdbd49 | 44 | " -o --operational-state=MIN_OPERSTATE[:MAX_OPERSTATE]\n" |
bb4f798a | 45 | " Required operational state\n" |
8b3d4ff0 MB |
46 | " -4 --ipv4 Requires at least one IPv4 address\n" |
47 | " -6 --ipv6 Requires at least one IPv6 address\n" | |
bb4f798a | 48 | " --any Wait until at least one of the interfaces is online\n" |
e735f4d4 | 49 | " --timeout=SECS Maximum time to wait for network connectivity\n" |
3a6ce677 BR |
50 | "\nSee the %s for details.\n", |
51 | program_invocation_short_name, | |
52 | link); | |
6e866b33 MB |
53 | |
54 | return 0; | |
60f067b4 JS |
55 | } |
56 | ||
46cdbd49 | 57 | static int parse_interface_with_operstate_range(const char *str) { |
bb4f798a | 58 | _cleanup_free_ char *ifname = NULL; |
5b5a102a | 59 | _cleanup_free_ LinkOperationalStateRange *range = NULL; |
bb4f798a MB |
60 | const char *p; |
61 | int r; | |
62 | ||
63 | assert(str); | |
64 | ||
46cdbd49 BR |
65 | range = new(LinkOperationalStateRange, 1); |
66 | if (!range) | |
67 | return log_oom(); | |
68 | ||
bb4f798a MB |
69 | p = strchr(str, ':'); |
70 | if (p) { | |
46cdbd49 BR |
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); | |
bb4f798a MB |
74 | |
75 | ifname = strndup(optarg, p - optarg); | |
76 | } else { | |
46cdbd49 BR |
77 | range->min = _LINK_OPERSTATE_INVALID; |
78 | range->max = _LINK_OPERSTATE_INVALID; | |
bb4f798a MB |
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 | ||
3a6ce677 BR |
88 | r = hashmap_ensure_put(&arg_interfaces, &string_hash_ops, ifname, TAKE_PTR(range)); |
89 | if (r == -ENOMEM) | |
bb4f798a | 90 | return log_oom(); |
bb4f798a MB |
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 | ||
60f067b4 JS |
101 | static int parse_argv(int argc, char *argv[]) { |
102 | ||
103 | enum { | |
104 | ARG_VERSION = 0x100, | |
e735f4d4 | 105 | ARG_IGNORE, |
bb4f798a | 106 | ARG_ANY, |
e735f4d4 | 107 | ARG_TIMEOUT, |
60f067b4 JS |
108 | }; |
109 | ||
110 | static const struct option options[] = { | |
bb4f798a MB |
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' }, | |
8b3d4ff0 MB |
117 | { "ipv4", no_argument, NULL, '4' }, |
118 | { "ipv6", no_argument, NULL, '6' }, | |
bb4f798a MB |
119 | { "any", no_argument, NULL, ARG_ANY }, |
120 | { "timeout", required_argument, NULL, ARG_TIMEOUT }, | |
60f067b4 JS |
121 | {} |
122 | }; | |
123 | ||
e735f4d4 | 124 | int c, r; |
60f067b4 JS |
125 | |
126 | assert(argc >= 0); | |
127 | assert(argv); | |
128 | ||
8b3d4ff0 | 129 | while ((c = getopt_long(argc, argv, "hi:qo:46", options, NULL)) >= 0) |
60f067b4 JS |
130 | |
131 | switch (c) { | |
132 | ||
133 | case 'h': | |
5eef597e MP |
134 | help(); |
135 | return 0; | |
60f067b4 JS |
136 | |
137 | case 'q': | |
138 | arg_quiet = true; | |
139 | break; | |
140 | ||
141 | case ARG_VERSION: | |
6300502b | 142 | return version(); |
60f067b4 JS |
143 | |
144 | case 'i': | |
46cdbd49 | 145 | r = parse_interface_with_operstate_range(optarg); |
bb4f798a MB |
146 | if (r < 0) |
147 | return r; | |
60f067b4 JS |
148 | break; |
149 | ||
e735f4d4 MP |
150 | case ARG_IGNORE: |
151 | if (strv_extend(&arg_ignore, optarg) < 0) | |
152 | return log_oom(); | |
153 | ||
154 | break; | |
155 | ||
bb4f798a | 156 | case 'o': { |
46cdbd49 BR |
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); | |
bb4f798a | 162 | |
46cdbd49 | 163 | arg_required_operstate = range; |
bb4f798a | 164 | |
bb4f798a MB |
165 | break; |
166 | } | |
8b3d4ff0 MB |
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 | ||
bb4f798a MB |
176 | case ARG_ANY: |
177 | arg_any = true; | |
178 | break; | |
179 | ||
e735f4d4 MP |
180 | case ARG_TIMEOUT: |
181 | r = parse_sec(optarg, &arg_timeout); | |
182 | if (r < 0) | |
183 | return r; | |
e735f4d4 MP |
184 | break; |
185 | ||
60f067b4 JS |
186 | case '?': |
187 | return -EINVAL; | |
188 | ||
189 | default: | |
ea0999c9 | 190 | assert_not_reached(); |
60f067b4 | 191 | } |
60f067b4 JS |
192 | |
193 | return 1; | |
194 | } | |
195 | ||
6e866b33 | 196 | static int run(int argc, char *argv[]) { |
5eef597e | 197 | _cleanup_(manager_freep) Manager *m = NULL; |
ea0999c9 | 198 | _unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL; |
5eef597e | 199 | int r; |
60f067b4 | 200 | |
3a6ce677 | 201 | log_setup(); |
60f067b4 | 202 | |
5eef597e MP |
203 | umask(0022); |
204 | ||
60f067b4 JS |
205 | r = parse_argv(argc, argv); |
206 | if (r <= 0) | |
207 | return r; | |
208 | ||
209 | if (arg_quiet) | |
bb4f798a | 210 | log_set_max_level(LOG_ERR); |
60f067b4 | 211 | |
86f210e9 | 212 | assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); |
60f067b4 | 213 | |
8b3d4ff0 | 214 | r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_required_family, arg_any, arg_timeout); |
6e866b33 MB |
215 | if (r < 0) |
216 | return log_error_errno(r, "Could not create manager: %m"); | |
60f067b4 | 217 | |
bb4f798a | 218 | if (manager_configured(m)) |
6e866b33 | 219 | goto success; |
60f067b4 | 220 | |
6e866b33 MB |
221 | notify_message = notify_start("READY=1\n" |
222 | "STATUS=Waiting for network connections...", | |
223 | "STATUS=Failed to wait for network connectivity..."); | |
60f067b4 JS |
224 | |
225 | r = sd_event_loop(m->event); | |
c3c690cd MB |
226 | if (r == -ETIMEDOUT) |
227 | return log_error_errno(r, "Timeout occurred while waiting for network connectivity."); | |
6e866b33 MB |
228 | if (r < 0) |
229 | return log_error_errno(r, "Event loop failed: %m"); | |
e735f4d4 | 230 | |
6e866b33 MB |
231 | success: |
232 | notify_message = "STATUS=All interfaces configured..."; | |
60f067b4 | 233 | |
6e866b33 | 234 | return 0; |
60f067b4 | 235 | } |
6e866b33 MB |
236 | |
237 | DEFINE_MAIN_FUNCTION(run); |