1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "alloc-util.h"
9 #include "pretty-print.h"
10 #include "process-util.h"
11 #include "reboot-util.h"
12 #include "systemctl-compat-halt.h"
13 #include "systemctl-compat-telinit.h"
14 #include "systemctl-logind.h"
15 #include "systemctl-util.h"
16 #include "systemctl.h"
17 #include "terminal-util.h"
18 #include "utmp-wtmp.h"
20 static int halt_help(void) {
21 _cleanup_free_
char *link
= NULL
;
24 r
= terminal_urlify_man("halt", "8", &link
);
28 printf("%s [OPTIONS...]%s\n"
29 "\n%s%s the system.%s\n"
31 " --help Show this help\n"
32 " --halt Halt the machine\n"
33 " -p --poweroff Switch off the machine\n"
34 " --reboot Reboot the machine\n"
35 " -f --force Force immediate halt/power-off/reboot\n"
36 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
37 " -d --no-wtmp Don't write wtmp record\n"
38 " --no-wall Don't send wall message before halt/power-off/reboot\n"
39 "\nSee the %s for details.\n"
40 , program_invocation_short_name
41 , arg_action
== ACTION_REBOOT
? " [ARG]" : ""
43 , arg_action
== ACTION_REBOOT
? "Reboot" :
44 arg_action
== ACTION_POWEROFF
? "Power off" :
53 int halt_parse_argv(int argc
, char *argv
[]) {
61 static const struct option options
[] = {
62 { "help", no_argument
, NULL
, ARG_HELP
},
63 { "halt", no_argument
, NULL
, ARG_HALT
},
64 { "poweroff", no_argument
, NULL
, 'p' },
65 { "reboot", no_argument
, NULL
, ARG_REBOOT
},
66 { "force", no_argument
, NULL
, 'f' },
67 { "wtmp-only", no_argument
, NULL
, 'w' },
68 { "no-wtmp", no_argument
, NULL
, 'd' },
69 { "no-sync", no_argument
, NULL
, 'n' },
70 { "no-wall", no_argument
, NULL
, ARG_NO_WALL
},
79 if (utmp_get_runlevel(&runlevel
, NULL
) >= 0)
80 if (IN_SET(runlevel
, '0', '6'))
83 while ((c
= getopt_long(argc
, argv
, "pfwdnih", options
, NULL
)) >= 0)
90 arg_action
= ACTION_HALT
;
94 if (arg_action
!= ACTION_REBOOT
)
95 arg_action
= ACTION_POWEROFF
;
99 arg_action
= ACTION_REBOOT
;
124 /* Compatibility nops */
131 assert_not_reached("Unhandled option");
134 if (arg_action
== ACTION_REBOOT
&& (argc
== optind
|| argc
== optind
+ 1)) {
135 r
= update_reboot_parameter_and_warn(argc
== optind
+ 1 ? argv
[optind
] : NULL
, false);
138 } else if (optind
< argc
)
139 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
140 "Too many arguments.");
145 int halt_main(void) {
148 r
= logind_check_inhibitors(arg_action
);
152 /* Delayed shutdown requested, and was successful */
153 if (arg_when
> 0 && logind_schedule_shutdown() == 0)
156 /* No delay, or logind failed or is not at all available */
157 if (geteuid() != 0) {
158 if (arg_dry_run
|| arg_force
> 0) {
159 (void) must_be_root();
163 /* Try logind if we are a normal user and no special mode applies. Maybe polkit allows us to
164 * shutdown the machine. */
165 if (IN_SET(arg_action
, ACTION_POWEROFF
, ACTION_REBOOT
, ACTION_HALT
)) {
166 r
= logind_reboot(arg_action
);
169 if (IN_SET(r
, -EOPNOTSUPP
, -EINPROGRESS
))
170 /* Requested operation is not supported on the local system or already in
174 /* on all other errors, try low-level operation */
178 /* In order to minimize the difference between operation with and without logind, we explicitly
179 * enable non-blocking mode for this, as logind's shutdown operations are always non-blocking. */
182 if (!arg_dry_run
&& !arg_force
)
183 return start_with_fallback();
185 assert(geteuid() == 0);
189 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
191 r
= utmp_put_shutdown();
193 log_warning_errno(r
, "Failed to write utmp record: %m");
200 r
= halt_now(arg_action
);
201 return log_error_errno(r
, "Failed to reboot: %m");