Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
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 LinkOperationalState arg_required_operstate = _LINK_OPERSTATE_INVALID;
22 : : static bool arg_any = false;
23 : :
24 : 0 : STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_keyp);
25 : 0 : STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep);
26 : :
27 : 0 : static int help(void) {
28 : 0 : _cleanup_free_ char *link = NULL;
29 : : int r;
30 : :
31 : 0 : r = terminal_urlify_man("systemd-networkd-wait-online.service", "8", &link);
32 [ # # ]: 0 : if (r < 0)
33 : 0 : return log_oom();
34 : :
35 : 0 : 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"
40 : : " -i --interface=INTERFACE[:OPERSTATE]\n"
41 : : " Block until at least these interfaces have appeared\n"
42 : : " --ignore=INTERFACE Don't take these interfaces into account\n"
43 : : " -o --operational-state=OPERSTATE\n"
44 : : " Required operational state\n"
45 : : " --any Wait until at least one of the interfaces is online\n"
46 : : " --timeout=SECS Maximum time to wait for network connectivity\n"
47 : : "\nSee the %s for details.\n"
48 : : , program_invocation_short_name
49 : : , link
50 : : );
51 : :
52 : 0 : return 0;
53 : : }
54 : :
55 : 0 : static int parse_interface_with_operstate(const char *str) {
56 : 0 : _cleanup_free_ char *ifname = NULL;
57 : : LinkOperationalState s;
58 : : const char *p;
59 : : int r;
60 : :
61 [ # # ]: 0 : assert(str);
62 : :
63 : 0 : p = strchr(str, ':');
64 [ # # ]: 0 : if (p) {
65 [ # # ]: 0 : if (isempty(p + 1))
66 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
67 : : "Operational state is empty.");
68 : :
69 : 0 : s = link_operstate_from_string(p + 1);
70 [ # # ]: 0 : if (s < 0)
71 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
72 : : "Invalid operational state '%s'", p + 1);
73 : :
74 : 0 : ifname = strndup(optarg, p - optarg);
75 : : } else {
76 : 0 : s = _LINK_OPERSTATE_INVALID;
77 : 0 : ifname = strdup(str);
78 : : }
79 [ # # ]: 0 : if (!ifname)
80 : 0 : return log_oom();
81 : :
82 [ # # ]: 0 : if (!ifname_valid(ifname))
83 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
84 : : "Invalid interface name '%s'", ifname);
85 : :
86 : 0 : r = hashmap_ensure_allocated(&arg_interfaces, &string_hash_ops);
87 [ # # ]: 0 : if (r < 0)
88 : 0 : return log_oom();
89 : :
90 : 0 : r = hashmap_put(arg_interfaces, ifname, INT_TO_PTR(s));
91 [ # # ]: 0 : if (r < 0)
92 [ # # ]: 0 : return log_error_errno(r, "Failed to store interface name: %m");
93 [ # # ]: 0 : if (r == 0)
94 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
95 : : "Interface name %s is already specified", ifname);
96 : :
97 : 0 : TAKE_PTR(ifname);
98 : 0 : return 0;
99 : : }
100 : :
101 : 0 : 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 : : { "any", no_argument, NULL, ARG_ANY },
118 : : { "timeout", required_argument, NULL, ARG_TIMEOUT },
119 : : {}
120 : : };
121 : :
122 : : int c, r;
123 : :
124 [ # # ]: 0 : assert(argc >= 0);
125 [ # # ]: 0 : assert(argv);
126 : :
127 [ # # ]: 0 : while ((c = getopt_long(argc, argv, "hi:qo:", options, NULL)) >= 0)
128 : :
129 [ # # # # : 0 : switch (c) {
# # # # #
# ]
130 : :
131 : 0 : case 'h':
132 : 0 : help();
133 : 0 : return 0;
134 : :
135 : 0 : case 'q':
136 : 0 : arg_quiet = true;
137 : 0 : break;
138 : :
139 : 0 : case ARG_VERSION:
140 : 0 : return version();
141 : :
142 : 0 : case 'i':
143 : 0 : r = parse_interface_with_operstate(optarg);
144 [ # # ]: 0 : if (r < 0)
145 : 0 : return r;
146 : 0 : break;
147 : :
148 : 0 : case ARG_IGNORE:
149 [ # # ]: 0 : if (strv_extend(&arg_ignore, optarg) < 0)
150 : 0 : return log_oom();
151 : :
152 : 0 : break;
153 : :
154 : 0 : case 'o': {
155 : : LinkOperationalState s;
156 : :
157 : 0 : s = link_operstate_from_string(optarg);
158 [ # # ]: 0 : if (s < 0)
159 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
160 : : "Invalid operational state '%s'", optarg);
161 : :
162 : 0 : arg_required_operstate = s;
163 : 0 : break;
164 : : }
165 : 0 : case ARG_ANY:
166 : 0 : arg_any = true;
167 : 0 : break;
168 : :
169 : 0 : case ARG_TIMEOUT:
170 : 0 : r = parse_sec(optarg, &arg_timeout);
171 [ # # ]: 0 : if (r < 0)
172 : 0 : return r;
173 : 0 : break;
174 : :
175 : 0 : case '?':
176 : 0 : return -EINVAL;
177 : :
178 : 0 : default:
179 : 0 : assert_not_reached("Unhandled option");
180 : : }
181 : :
182 : 0 : return 1;
183 : : }
184 : :
185 : 0 : static int run(int argc, char *argv[]) {
186 : 0 : _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
187 : 0 : _cleanup_(manager_freep) Manager *m = NULL;
188 : : int r;
189 : :
190 : 0 : log_setup_service();
191 : :
192 : 0 : umask(0022);
193 : :
194 : 0 : r = parse_argv(argc, argv);
195 [ # # ]: 0 : if (r <= 0)
196 : 0 : return r;
197 : :
198 [ # # ]: 0 : if (arg_quiet)
199 : 0 : log_set_max_level(LOG_ERR);
200 : :
201 [ # # ]: 0 : assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
202 : :
203 : 0 : r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_any, arg_timeout);
204 [ # # ]: 0 : if (r < 0)
205 [ # # ]: 0 : return log_error_errno(r, "Could not create manager: %m");
206 : :
207 [ # # ]: 0 : if (manager_configured(m))
208 : 0 : goto success;
209 : :
210 : 0 : notify_message = notify_start("READY=1\n"
211 : : "STATUS=Waiting for network connections...",
212 : : "STATUS=Failed to wait for network connectivity...");
213 : :
214 : 0 : r = sd_event_loop(m->event);
215 [ # # ]: 0 : if (r < 0)
216 [ # # ]: 0 : return log_error_errno(r, "Event loop failed: %m");
217 : :
218 : 0 : success:
219 : 0 : notify_message = "STATUS=All interfaces configured...";
220 : :
221 : 0 : return 0;
222 : : }
223 : :
224 : 0 : DEFINE_MAIN_FUNCTION(run);
|