• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14766779411

30 Apr 2025 04:55PM UTC coverage: 72.225% (-0.06%) from 72.282%
14766779411

push

github

web-flow
wait-online: handle varlink connection errors while waiting for DNS (#37283)

Currently, if systemd-networkd-wait-online is started with --dns, and
systemd-resolved is not running, it will exit with an error right away.
Similarly, if systemd-resolved is restarted while waiting for DNS
configuration, systemd-networkd-wait-online will not attempt to
re-connect, and will potentially never see subsequent DNS
configurations.

Improve this by adding socket units for the systemd-resolved varlink
servers, and re-establish the connection in systemd-networkd-wait-online
when we receive `SD_VARLINK_ERROR_DISCONNECTED`.

8 of 16 new or added lines in 2 files covered. (50.0%)

5825 existing lines in 217 files now uncovered.

297168 of 411450 relevant lines covered (72.22%)

695892.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

44.84
/src/systemctl/systemctl-logind.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <unistd.h>
4

5
#include "sd-login.h"
6

7
#include "bus-error.h"
8
#include "bus-locator.h"
9
#include "login-util.h"
10
#include "mountpoint-util.h"
11
#include "process-util.h"
12
#include "systemctl.h"
13
#include "systemctl-logind.h"
14
#include "systemctl-start-unit.h"
15
#include "systemctl-util.h"
16
#include "terminal-util.h"
17
#include "user-util.h"
18

19
static int logind_set_wall_message(sd_bus *bus) {
38✔
20
#if ENABLE_LOGIND
21
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
22
        _cleanup_free_ char *m = NULL;
38✔
23
        int r;
38✔
24

25
        assert(bus);
38✔
26

27
        m = strv_join(arg_wall, " ");
38✔
28
        if (!m)
38✔
29
                return log_oom();
×
30

31
        log_debug("%s wall message \"%s\".", arg_dry_run ? "Would set" : "Setting", m);
43✔
32
        if (arg_dry_run)
38✔
33
                return 0;
34

35
        r = bus_call_method(bus, bus_login_mgr, "SetWallMessage", &error, NULL, "sb", m, !arg_no_wall);
25✔
36
        if (r < 0)
25✔
37
                return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
×
38
#endif
39
        return 0;
40
}
41

42
/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
43
int logind_reboot(enum action a) {
32✔
44
#if ENABLE_LOGIND
45
        static const char* actions[_ACTION_MAX] = {
32✔
46
                [ACTION_POWEROFF]               = "PowerOff",
47
                [ACTION_REBOOT]                 = "Reboot",
48
                [ACTION_KEXEC]                  = "Reboot",
49
                [ACTION_SOFT_REBOOT]            = "Reboot",
50
                [ACTION_HALT]                   = "Halt",
51
                [ACTION_SUSPEND]                = "Suspend",
52
                [ACTION_HIBERNATE]              = "Hibernate",
53
                [ACTION_HYBRID_SLEEP]           = "HybridSleep",
54
                [ACTION_SUSPEND_THEN_HIBERNATE] = "SuspendThenHibernate",
55
                [ACTION_SLEEP]                  = "Sleep",
56
        };
57

58
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
32✔
59
        uint64_t flags = 0;
32✔
60
        sd_bus *bus;
32✔
61
        int r;
32✔
62

63
        assert(a >= 0);
32✔
64
        assert(a < _ACTION_MAX);
32✔
65

66
        if (!actions[a])
32✔
67
                return -EINVAL;
68

69
        r = acquire_bus_full(BUS_FULL, /* graceful = */ true, &bus);
32✔
70
        if (r < 0)
32✔
71
                return r;
72

73
        polkit_agent_open_maybe();
32✔
74
        (void) logind_set_wall_message(bus);
32✔
75

76
        const char *method_with_flags = a == ACTION_SLEEP ? actions[a] : strjoina(actions[a], "WithFlags");
160✔
77

78
        log_debug("%s org.freedesktop.login1.Manager %s dbus call.",
37✔
79
                  arg_dry_run ? "Would execute" : "Executing", method_with_flags);
80

81
        if (arg_dry_run)
32✔
82
                return 0;
83

84
        SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0);
19✔
85
        SET_FLAG(flags, SD_LOGIND_SKIP_INHIBITORS, arg_check_inhibitors == 0);
19✔
86
        SET_FLAG(flags,
19✔
87
                 SD_LOGIND_REBOOT_VIA_KEXEC,
88
                 a == ACTION_KEXEC || (a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_KEXEC") <= 0));
89
        /* Try to soft-reboot if /run/nextroot/ is a valid OS tree, but only if it's also a mount point.
90
         * Otherwise, if people store new rootfs directly on /run/ tmpfs, 'systemctl reboot' would always
91
         * soft-reboot, as /run/nextroot/ can never go away. */
92
        SET_FLAG(flags,
24✔
93
                 SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP,
94
                 a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT") <= 0 && path_is_mount_point("/run/nextroot") > 0);
95
        SET_FLAG(flags, SD_LOGIND_SOFT_REBOOT, a == ACTION_SOFT_REBOOT);
19✔
96

97
        r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
19✔
98
        if (r < 0 && FLAGS_SET(flags, SD_LOGIND_SKIP_INHIBITORS) &&
19✔
99
                        sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
×
100
                sd_bus_error_free(&error);
×
101
                flags &= ~SD_LOGIND_SKIP_INHIBITORS;
×
102
                r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
×
103
        }
104
        if (r < 0 && FLAGS_SET(flags, SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP) &&
×
105
                        sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
×
106
                sd_bus_error_free(&error);
×
107
                flags &= ~SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP;
×
108
                r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
×
109
        }
110
        if (r >= 0)
×
111
                return 0;
19✔
112
        if (geteuid() == 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED))
×
113
                return log_error_errno(r,
×
114
                                       "The current polkit policy does not allow root to ignore inhibitors without authentication in order to %s.\n"
115
                                       "To allow this action, a new polkit rule is needed.\n"
116
                                       "See " POLKIT_RULES_DIR "/10-systemd-logind-root-ignore-inhibitors.rules.example.",
117
                                       action_table[a].verb);
118
        if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD) || a == ACTION_SLEEP)
×
119
                return log_error_errno(r, "Call to %s failed: %s", actions[a], bus_error_message(&error, r));
×
120

121
        /* Fall back to original methods in case there is an older version of systemd-logind */
122
        log_debug("Method %s not available: %s. Falling back to %s", method_with_flags, bus_error_message(&error, r), actions[a]);
×
123
        sd_bus_error_free(&error);
×
124

125
        r = bus_call_method(bus, bus_login_mgr, actions[a], &error, NULL, "b", arg_ask_password);
×
126
        if (r < 0)
×
127
                return log_error_errno(r, "Call to %s failed: %s", actions[a], bus_error_message(&error, r));
×
128

129
        return 0;
130
#else
131
        return -ENOSYS;
132
#endif
133
}
134

135
int logind_check_inhibitors(enum action a) {
43✔
136
#if ENABLE_LOGIND
137
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
43✔
138
        _cleanup_strv_free_ char **sessions = NULL;
43✔
139
        const char *what, *who, *why, *mode;
43✔
140
        uint32_t uid, pid;
43✔
141
        sd_bus *bus;
43✔
142
        unsigned c = 0;
43✔
143
        int r;
43✔
144

145
        assert(a >= 0);
43✔
146
        assert(a < _ACTION_MAX);
43✔
147

148
        if (arg_check_inhibitors == 0 || arg_force > 0)
43✔
149
                return 0;
150

151
        if (arg_when > 0)
37✔
152
                return 0;
153

154
        if (arg_check_inhibitors < 0 && !on_tty())
37✔
155
                return 0;
156

157
        if (arg_transport != BUS_TRANSPORT_LOCAL)
×
158
                return 0;
159

160
        r = acquire_bus_full(BUS_FULL, /* graceful = */ true, &bus);
×
161
        if ((ERRNO_IS_NEG_DISCONNECT(r) || r == -ENOENT) && geteuid() == 0)
×
162
                return 0; /* When D-Bus is not running (ECONNREFUSED) or D-Bus socket is not created (ENOENT),
163
                           * allow root to force a shutdown. E.g. when running at the emergency console. */
164
        if (r < 0)
×
165
                return r;
166

167
        r = bus_call_method(bus, bus_login_mgr, "ListInhibitors", NULL, &reply, NULL);
×
168
        if (r < 0)
×
169
                /* If logind is not around, then there are no inhibitors... */
170
                return 0;
171

172
        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
×
173
        if (r < 0)
×
174
                return bus_log_parse_error(r);
×
175

176
        while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
×
177
                _cleanup_free_ char *comm = NULL, *user = NULL;
×
178
                _cleanup_strv_free_ char **sv = NULL;
×
179

180
                if (!STR_IN_SET(mode, "block", "block-weak"))
×
181
                        continue;
×
182

183
                if (streq(mode, "block-weak") && (geteuid() == 0 || geteuid() == uid || !on_tty()))
×
184
                        continue;
×
185

186
                sv = strv_split(what, ":");
×
187
                if (!sv)
×
188
                        return log_oom();
×
189

190
                if (!pid_is_valid((pid_t) pid))
×
191
                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid PID "PID_FMT".", (pid_t) pid);
×
192

193
                if (!strv_contains(sv,
×
194
                                   IN_SET(a,
195
                                          ACTION_HALT,
196
                                          ACTION_POWEROFF,
197
                                          ACTION_REBOOT,
198
                                          ACTION_KEXEC) ? "shutdown" : "sleep"))
199
                        continue;
×
200

201
                (void) pid_get_comm(pid, &comm);
×
202
                user = uid_to_name(uid);
×
203

204
                log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
×
205
                            who, (pid_t) pid, strna(comm), strna(user), why);
206

207
                c++;
×
208
        }
209
        if (r < 0)
×
210
                return bus_log_parse_error(r);
×
211

212
        r = sd_bus_message_exit_container(reply);
×
213
        if (r < 0)
×
214
                return bus_log_parse_error(r);
×
215

216
        /* root respects inhibitors since v257 but keeps ignoring sessions by default */
217
        if (arg_check_inhibitors < 0 && c == 0 && geteuid() == 0)
×
218
                return 0;
219

220
        /* Check for current sessions */
221
        sd_get_sessions(&sessions);
×
222
        STRV_FOREACH(s, sessions) {
×
223
                _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
×
224

225
                if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
×
226
                        continue;
×
227

228
                if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
×
229
                        continue;
×
230

231
                if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
×
232
                        continue;
×
233

234
                sd_session_get_tty(*s, &tty);
×
235
                sd_session_get_seat(*s, &seat);
×
236
                sd_session_get_service(*s, &service);
×
237
                user = uid_to_name(uid);
×
238

239
                log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
×
240
                c++;
×
241
        }
242

243
        if (c <= 0)
×
244
                return 0;
245

UNCOV
246
        return log_error_errno(SYNTHETIC_ERRNO(EPERM),
×
247
                               "Please retry operation after closing inhibitors and logging out other users.\n"
248
                               "'systemd-inhibit' can be used to list active inhibitors.\n"
249
                               "Alternatively, ignore inhibitors and users with 'systemctl %s -i'.",
250
                               action_table[a].verb);
251
#else
252
        return 0;
253
#endif
254
}
255

256
int prepare_firmware_setup(void) {
29✔
257

258
        if (!arg_firmware_setup)
29✔
259
                return 0;
29✔
260

261
#if ENABLE_LOGIND
262
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
263
        sd_bus *bus;
×
264
        int r;
×
265

266
        r = acquire_bus(BUS_FULL, &bus);
×
267
        if (r < 0)
×
268
                return r;
269

270
        r = bus_call_method(bus, bus_login_mgr, "SetRebootToFirmwareSetup", &error, NULL, "b", true);
×
271
        if (r < 0)
×
272
                return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
×
273

274
        return 0;
275
#else
276
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
277
                               "Booting into firmware setup not supported.");
278
#endif
279
}
280

281
int prepare_boot_loader_menu(void) {
29✔
282

283
        if (arg_boot_loader_menu == USEC_INFINITY)
29✔
284
                return 0;
29✔
285

286
#if ENABLE_LOGIND
287
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
288
        sd_bus *bus;
×
289
        int r;
×
290

291
        r = acquire_bus(BUS_FULL, &bus);
×
292
        if (r < 0)
×
293
                return r;
294

295
        r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderMenu", &error, NULL, "t", arg_boot_loader_menu);
×
296
        if (r < 0)
×
297
                return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
×
298

299
        return 0;
300
#else
301
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
302
                               "Booting into boot loader menu not supported.");
303
#endif
304
}
305

306
int prepare_boot_loader_entry(void) {
29✔
307

308
        if (!arg_boot_loader_entry)
29✔
309
                return 0;
29✔
310

311
#if ENABLE_LOGIND
312
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
313
        sd_bus *bus;
×
314
        int r;
×
315

316
        r = acquire_bus(BUS_FULL, &bus);
×
317
        if (r < 0)
×
318
                return r;
319

320
        r = bus_call_method(bus, bus_login_mgr, "SetRebootToBootLoaderEntry", &error, NULL, "s", arg_boot_loader_entry);
×
321
        if (r < 0)
×
322
                return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
×
323

324
        return 0;
325
#else
326
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
327
                               "Booting into boot loader entry not supported.");
328
#endif
329
}
330

331
int logind_schedule_shutdown(enum action a) {
3✔
332
#if ENABLE_LOGIND
333
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3✔
334
        const char *action;
3✔
335
        sd_bus *bus;
3✔
336
        int r;
3✔
337

338
        assert(a >= 0);
3✔
339
        assert(a < _ACTION_MAX);
3✔
340

341
        r = acquire_bus(BUS_FULL, &bus);
3✔
342
        if (r < 0)
3✔
343
                return r;
344

345
        action = action_table[a].verb;
3✔
346
        if (!action)
3✔
347
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Scheduling not supported for this action.");
×
348

349
        if (arg_dry_run)
3✔
350
                action = strjoina("dry-", action);
×
351

352
        (void) logind_set_wall_message(bus);
3✔
353

354
        r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when);
3✔
355
        if (r < 0)
3✔
356
                return log_warning_errno(r, "Failed to schedule shutdown: %s", bus_error_message(&error, r));
×
357

358
        if (!arg_quiet)
3✔
359
                logind_show_shutdown();
3✔
360

361
        return 0;
362
#else
363
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
364
                               "Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
365
#endif
366
}
367

368
int logind_cancel_shutdown(void) {
3✔
369
#if ENABLE_LOGIND
370
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3✔
371
        sd_bus *bus;
3✔
372
        int r;
3✔
373

374
        r = acquire_bus(BUS_FULL, &bus);
3✔
375
        if (r < 0)
3✔
376
                return r;
377

378
        (void) logind_set_wall_message(bus);
3✔
379

380
        r = bus_call_method(bus, bus_login_mgr, "CancelScheduledShutdown", &error, NULL, NULL);
3✔
381
        if (r < 0)
3✔
382
                return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
×
383

384
        return 0;
385
#else
386
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
387
                               "Not compiled with logind support, cannot cancel scheduled shutdowns.");
388
#endif
389
}
390

391
int logind_show_shutdown(void) {
4✔
392
#if ENABLE_LOGIND
393
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
394
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4✔
395
        sd_bus *bus;
4✔
396
        const char *action, *pretty_action;
4✔
397
        uint64_t elapse;
4✔
398
        int r;
4✔
399

400
        r = acquire_bus(BUS_FULL, &bus);
4✔
401
        if (r < 0)
4✔
402
                return r;
403

404
        r = bus_get_property(bus, bus_login_mgr, "ScheduledShutdown", &error, &reply, "(st)");
4✔
405
        if (r < 0)
4✔
406
                return log_error_errno(r, "Failed to query scheduled shutdown: %s", bus_error_message(&error, r));
×
407

408
        r = sd_bus_message_read(reply, "(st)", &action, &elapse);
4✔
409
        if (r < 0)
4✔
410
                return r;
411

412
        if (isempty(action))
4✔
413
                return log_full_errno(arg_quiet ? LOG_DEBUG : LOG_ERR, SYNTHETIC_ERRNO(ENODATA), "No scheduled shutdown.");
×
414

415
        if (STR_IN_SET(action, "halt", "poweroff", "exit"))
4✔
416
                pretty_action = "Shutdown";
417
        else if (streq(action, "kexec"))
2✔
418
                pretty_action = "Reboot via kexec";
419
        else if (streq(action, "reboot"))
2✔
420
                pretty_action = "Reboot";
421
        else /* If we don't recognize the action string, we'll show it as-is */
422
                pretty_action = action;
×
423

424
        if (IN_SET(arg_action, ACTION_SYSTEMCTL, ACTION_SYSTEMCTL_SHOW_SHUTDOWN))
4✔
425
                log_info("%s scheduled for %s, use 'systemctl %s --when=cancel' to cancel.",
×
426
                         pretty_action,
427
                         FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style),
428
                         action);
429
        else
430
                log_info("%s scheduled for %s, use 'shutdown -c' to cancel.",
4✔
431
                         pretty_action,
432
                         FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style));
433

434
        return 0;
435
#else
436
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
437
                               "Not compiled with logind support, cannot show scheduled shutdowns.");
438
#endif
439
}
440

441
int help_boot_loader_entry(void) {
×
442
#if ENABLE_LOGIND
443
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
444
        _cleanup_strv_free_ char **l = NULL;
×
445
        sd_bus *bus;
×
446
        int r;
×
447

448
        /* This is called without checking runtime scope and bus transport like we do in parse_argv().
449
         * Loading boot entries is only supported by system scope. Let's gracefully adjust them. */
450
        arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
×
451
        if (arg_transport == BUS_TRANSPORT_CAPSULE) {
×
452
                arg_host = NULL;
×
453
                arg_transport = BUS_TRANSPORT_LOCAL;
×
454
        }
455

456
        r = acquire_bus(BUS_FULL, &bus);
×
457
        if (r < 0)
×
458
                return r;
459

460
        r = bus_get_property_strv(bus, bus_login_mgr, "BootLoaderEntries", &error, &l);
×
461
        if (r < 0)
×
462
                return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
×
463

464
        if (strv_isempty(l))
×
465
                return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No boot loader entries discovered.");
×
466

467
        STRV_FOREACH(i, l)
×
468
                puts(*i);
×
469

470
        return 0;
471
#else
472
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
473
                               "Not compiled with logind support, cannot display boot loader entries.");
474
#endif
475
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc