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