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

systemd / systemd / 20447389715

21 Dec 2025 07:31PM UTC coverage: 72.37% (-0.1%) from 72.5%
20447389715

push

github

DaanDeMeyer
mkosi: Use initrd as exitrd

Let's speed up image builds by avoiding building
an exitrd and instead reusing the initrd image for
the same purpose.

308584 of 426400 relevant lines covered (72.37%)

1134231.7 hits per line

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

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

3
#include <unistd.h>
4

5
#include "sd-bus.h"
6
#include "sd-login.h"
7

8
#include "bus-error.h"
9
#include "bus-locator.h"
10
#include "bus-util.h"
11
#include "env-util.h"
12
#include "errno-util.h"
13
#include "format-util.h"
14
#include "log.h"
15
#include "login-util.h"
16
#include "mountpoint-util.h"
17
#include "process-util.h"
18
#include "runtime-scope.h"
19
#include "string-util.h"
20
#include "strv.h"
21
#include "systemctl.h"
22
#include "systemctl-logind.h"
23
#include "systemctl-start-unit.h"
24
#include "systemctl-util.h"
25
#include "terminal-util.h"
26
#include "time-util.h"
27
#include "user-util.h"
28

29
static int logind_set_wall_message(sd_bus *bus) {
39✔
30
#if ENABLE_LOGIND
31
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
32
        _cleanup_free_ char *m = NULL;
39✔
33
        int r;
39✔
34

35
        assert(bus);
39✔
36

37
        m = strv_join(arg_wall, " ");
39✔
38
        if (!m)
39✔
39
                return log_oom();
×
40

41
        log_debug("%s wall message \"%s\".", arg_dry_run ? "Would set" : "Setting", m);
45✔
42
        if (arg_dry_run)
39✔
43
                return 0;
44

45
        r = bus_call_method(bus, bus_login_mgr, "SetWallMessage", &error, NULL, "sb", m, !arg_no_wall);
26✔
46
        if (r < 0)
26✔
47
                return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
×
48
#endif
49
        return 0;
50
}
51

52
/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
53
int logind_reboot(enum action a) {
33✔
54
#if ENABLE_LOGIND
55
        static const char* actions[_ACTION_MAX] = {
33✔
56
                [ACTION_POWEROFF]               = "PowerOff",
57
                [ACTION_REBOOT]                 = "Reboot",
58
                [ACTION_KEXEC]                  = "Reboot",
59
                [ACTION_SOFT_REBOOT]            = "Reboot",
60
                [ACTION_HALT]                   = "Halt",
61
                [ACTION_SUSPEND]                = "Suspend",
62
                [ACTION_HIBERNATE]              = "Hibernate",
63
                [ACTION_HYBRID_SLEEP]           = "HybridSleep",
64
                [ACTION_SUSPEND_THEN_HIBERNATE] = "SuspendThenHibernate",
65
                [ACTION_SLEEP]                  = "Sleep",
66
        };
67

68
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
33✔
69
        uint64_t flags = 0;
33✔
70
        sd_bus *bus;
33✔
71
        int r;
33✔
72

73
        assert(a >= 0);
33✔
74
        assert(a < _ACTION_MAX);
33✔
75

76
        if (!actions[a])
33✔
77
                return -EINVAL;
78

79
        r = acquire_bus_full(BUS_FULL, /* graceful= */ true, &bus);
33✔
80
        if (r < 0)
33✔
81
                return r;
82

83
        polkit_agent_open_maybe();
33✔
84
        (void) logind_set_wall_message(bus);
33✔
85

86
        const char *method_with_flags = a == ACTION_SLEEP ? actions[a] : strjoina(actions[a], "WithFlags");
165✔
87

88
        log_debug("%s org.freedesktop.login1.Manager %s dbus call.",
39✔
89
                  arg_dry_run ? "Would execute" : "Executing", method_with_flags);
90

91
        if (arg_dry_run)
33✔
92
                return 0;
93

94
        SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0);
20✔
95
        SET_FLAG(flags, SD_LOGIND_SKIP_INHIBITORS, arg_check_inhibitors == 0);
20✔
96
        SET_FLAG(flags,
20✔
97
                 SD_LOGIND_REBOOT_VIA_KEXEC,
98
                 a == ACTION_KEXEC || (a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_KEXEC") <= 0));
99
        /* Try to soft-reboot if /run/nextroot/ is a valid OS tree, but only if it's also a mount point.
100
         * Otherwise, if people store new rootfs directly on /run/ tmpfs, 'systemctl reboot' would always
101
         * soft-reboot, as /run/nextroot/ can never go away. */
102
        SET_FLAG(flags,
25✔
103
                 SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP,
104
                 a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT") <= 0 && path_is_mount_point("/run/nextroot") > 0);
105
        SET_FLAG(flags, SD_LOGIND_SOFT_REBOOT, a == ACTION_SOFT_REBOOT);
20✔
106

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

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

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

139
        return 0;
140
#else
141
        return -ENOSYS;
142
#endif
143
}
144

145
int logind_check_inhibitors(enum action a) {
43✔
146
#if ENABLE_LOGIND
147
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
43✔
148
        _cleanup_strv_free_ char **sessions = NULL;
43✔
149
        const char *what, *who, *why, *mode;
43✔
150
        uint32_t uid, pid;
43✔
151
        sd_bus *bus;
43✔
152
        unsigned c = 0;
43✔
153
        int r;
43✔
154

155
        assert(a >= 0);
43✔
156
        assert(a < _ACTION_MAX);
43✔
157

158
        if (arg_check_inhibitors == 0 || arg_force > 0)
43✔
159
                return 0;
160

161
        if (arg_when > 0)
37✔
162
                return 0;
163

164
        if (arg_check_inhibitors < 0 && !on_tty())
37✔
165
                return 0;
166

167
        if (arg_transport != BUS_TRANSPORT_LOCAL)
1✔
168
                return 0;
169

170
        r = acquire_bus_full(BUS_FULL, /* graceful= */ true, &bus);
1✔
171
        if ((ERRNO_IS_NEG_DISCONNECT(r) || r == -ENOENT) && geteuid() == 0)
1✔
172
                return 0; /* When D-Bus is not running (ECONNREFUSED) or D-Bus socket is not created (ENOENT),
173
                           * allow root to force a shutdown. E.g. when running at the emergency console. */
174
        if (r < 0)
1✔
175
                return r;
176

177
        r = bus_call_method(bus, bus_login_mgr, "ListInhibitors", NULL, &reply, NULL);
1✔
178
        if (r < 0)
1✔
179
                /* If logind is not around, then there are no inhibitors... */
180
                return 0;
181

182
        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
1✔
183
        if (r < 0)
1✔
184
                return bus_log_parse_error(r);
×
185

186
        while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
2✔
187
                _cleanup_free_ char *comm = NULL, *user = NULL;
1✔
188
                _cleanup_strv_free_ char **sv = NULL;
1✔
189

190
                if (!STR_IN_SET(mode, "block", "block-weak"))
1✔
191
                        continue;
1✔
192

193
                if (streq(mode, "block-weak") && (geteuid() == 0 || geteuid() == uid || !on_tty()))
×
194
                        continue;
×
195

196
                sv = strv_split(what, ":");
×
197
                if (!sv)
×
198
                        return log_oom();
×
199

200
                if (!pid_is_valid((pid_t) pid))
×
201
                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid PID "PID_FMT".", (pid_t) pid);
×
202

203
                if (!strv_contains(sv,
×
204
                                   IN_SET(a,
205
                                          ACTION_HALT,
206
                                          ACTION_POWEROFF,
207
                                          ACTION_REBOOT,
208
                                          ACTION_KEXEC) ? "shutdown" : "sleep"))
209
                        continue;
×
210

211
                (void) pid_get_comm(pid, &comm);
×
212
                user = uid_to_name(uid);
×
213

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

217
                c++;
×
218
        }
219
        if (r < 0)
1✔
220
                return bus_log_parse_error(r);
×
221

222
        r = sd_bus_message_exit_container(reply);
1✔
223
        if (r < 0)
1✔
224
                return bus_log_parse_error(r);
×
225

226
        /* root respects inhibitors since v257 but keeps ignoring sessions by default */
227
        if (arg_check_inhibitors < 0 && c == 0 && geteuid() == 0)
1✔
228
                return 0;
229

230
        /* Check for current sessions */
231
        sd_get_sessions(&sessions);
1✔
232
        STRV_FOREACH(s, sessions) {
2✔
233
                _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1✔
234

235
                if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1✔
236
                        continue;
×
237

238
                if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1✔
239
                        continue;
1✔
240

241
                if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
×
242
                        continue;
×
243

244
                sd_session_get_tty(*s, &tty);
×
245
                sd_session_get_seat(*s, &seat);
×
246
                sd_session_get_service(*s, &service);
×
247
                user = uid_to_name(uid);
×
248

249
                log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
×
250
                c++;
×
251
        }
252

253
        if (c <= 0)
1✔
254
                return 0;
255

256
        return log_error_errno(SYNTHETIC_ERRNO(EPERM),
×
257
                               "Please retry operation after closing inhibitors and logging out other users.\n"
258
                               "'systemd-inhibit' can be used to list active inhibitors.\n"
259
                               "Alternatively, ignore inhibitors and users with 'systemctl %s -i'.",
260
                               action_table[a].verb);
261
#else
262
        return 0;
263
#endif
264
}
265

266
int prepare_firmware_setup(void) {
29✔
267

268
        if (!arg_firmware_setup)
29✔
269
                return 0;
29✔
270

271
#if ENABLE_LOGIND
272
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
273
        sd_bus *bus;
×
274
        int r;
×
275

276
        r = acquire_bus(BUS_FULL, &bus);
×
277
        if (r < 0)
×
278
                return r;
279

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

284
        return 0;
285
#else
286
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
287
                               "Booting into firmware setup not supported.");
288
#endif
289
}
290

291
int prepare_boot_loader_menu(void) {
29✔
292

293
        if (arg_boot_loader_menu == USEC_INFINITY)
29✔
294
                return 0;
29✔
295

296
#if ENABLE_LOGIND
297
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
298
        sd_bus *bus;
×
299
        int r;
×
300

301
        r = acquire_bus(BUS_FULL, &bus);
×
302
        if (r < 0)
×
303
                return r;
304

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

309
        return 0;
310
#else
311
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
312
                               "Booting into boot loader menu not supported.");
313
#endif
314
}
315

316
int prepare_boot_loader_entry(void) {
29✔
317

318
        if (!arg_boot_loader_entry)
29✔
319
                return 0;
29✔
320

321
#if ENABLE_LOGIND
322
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
323
        sd_bus *bus;
×
324
        int r;
×
325

326
        r = acquire_bus(BUS_FULL, &bus);
×
327
        if (r < 0)
×
328
                return r;
329

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

334
        return 0;
335
#else
336
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
337
                               "Booting into boot loader entry not supported.");
338
#endif
339
}
340

341
int logind_schedule_shutdown(enum action a) {
3✔
342
#if ENABLE_LOGIND
343
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3✔
344
        const char *action;
3✔
345
        sd_bus *bus;
3✔
346
        int r;
3✔
347

348
        assert(a >= 0);
3✔
349
        assert(a < _ACTION_MAX);
3✔
350

351
        r = acquire_bus(BUS_FULL, &bus);
3✔
352
        if (r < 0)
3✔
353
                return r;
354

355
        action = action_table[a].verb;
3✔
356
        if (!action)
3✔
357
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Scheduling not supported for this action.");
×
358

359
        if (arg_dry_run)
3✔
360
                action = strjoina("dry-", action);
×
361

362
        (void) logind_set_wall_message(bus);
3✔
363

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

368
        if (!arg_quiet)
3✔
369
                logind_show_shutdown();
3✔
370

371
        return 0;
372
#else
373
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
374
                               "Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
375
#endif
376
}
377

378
int logind_cancel_shutdown(void) {
3✔
379
#if ENABLE_LOGIND
380
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3✔
381
        sd_bus *bus;
3✔
382
        int r;
3✔
383

384
        r = acquire_bus(BUS_FULL, &bus);
3✔
385
        if (r < 0)
3✔
386
                return r;
387

388
        (void) logind_set_wall_message(bus);
3✔
389

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

394
        return 0;
395
#else
396
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
397
                               "Not compiled with logind support, cannot cancel scheduled shutdowns.");
398
#endif
399
}
400

401
int logind_show_shutdown(void) {
4✔
402
#if ENABLE_LOGIND
403
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
404
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4✔
405
        sd_bus *bus;
4✔
406
        const char *action, *pretty_action;
4✔
407
        uint64_t elapse;
4✔
408
        int r;
4✔
409

410
        r = acquire_bus(BUS_FULL, &bus);
4✔
411
        if (r < 0)
4✔
412
                return r;
413

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

418
        r = sd_bus_message_read(reply, "(st)", &action, &elapse);
4✔
419
        if (r < 0)
4✔
420
                return r;
421

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

425
        if (STR_IN_SET(action, "halt", "poweroff", "exit"))
4✔
426
                pretty_action = "Shutdown";
427
        else if (streq(action, "kexec"))
2✔
428
                pretty_action = "Reboot via kexec";
429
        else if (streq(action, "reboot"))
2✔
430
                pretty_action = "Reboot";
431
        else /* If we don't recognize the action string, we'll show it as-is */
432
                pretty_action = action;
×
433

434
        if (IN_SET(arg_action, ACTION_SYSTEMCTL, ACTION_SYSTEMCTL_SHOW_SHUTDOWN))
4✔
435
                log_info("%s scheduled for %s, use 'systemctl %s --when=cancel' to cancel.",
×
436
                         pretty_action,
437
                         FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style),
438
                         action);
439
        else
440
                log_info("%s scheduled for %s, use 'shutdown -c' to cancel.",
4✔
441
                         pretty_action,
442
                         FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style));
443

444
        return 0;
445
#else
446
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
447
                               "Not compiled with logind support, cannot show scheduled shutdowns.");
448
#endif
449
}
450

451
int help_boot_loader_entry(void) {
×
452
#if ENABLE_LOGIND
453
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
454
        _cleanup_strv_free_ char **l = NULL;
×
455
        sd_bus *bus;
×
456
        int r;
×
457

458
        /* This is called without checking runtime scope and bus transport like we do in parse_argv().
459
         * Loading boot entries is only supported by system scope. Let's gracefully adjust them. */
460
        arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
×
461
        if (arg_transport == BUS_TRANSPORT_CAPSULE) {
×
462
                arg_host = NULL;
×
463
                arg_transport = BUS_TRANSPORT_LOCAL;
×
464
        }
465

466
        r = acquire_bus(BUS_FULL, &bus);
×
467
        if (r < 0)
×
468
                return r;
469

470
        r = bus_get_property_strv(bus, bus_login_mgr, "BootLoaderEntries", &error, &l);
×
471
        if (r < 0)
×
472
                return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
×
473

474
        if (strv_isempty(l))
×
475
                return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No boot loader entries discovered.");
×
476

477
        STRV_FOREACH(i, l)
×
478
                puts(*i);
×
479

480
        return 0;
481
#else
482
        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
483
                               "Not compiled with logind support, cannot display boot loader entries.");
484
#endif
485
}
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