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-start-unit.h"
16 #include "systemctl-util.h"
17 #include "systemctl.h"
18 #include "terminal-util.h"
19 #include "utmp-wtmp.h"
21 static int halt_help(void) {
22 _cleanup_free_
char *link
= NULL
;
25 r
= terminal_urlify_man("halt", "8", &link
);
29 printf("%s [OPTIONS...]%s\n"
30 "\n%s%s the system.%s\n"
32 " --help Show this help\n"
33 " --halt Halt the machine\n"
34 " -p --poweroff Switch off the machine\n"
35 " --reboot Reboot the machine\n"
36 " -f --force Force immediate halt/power-off/reboot\n"
37 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
38 " -d --no-wtmp Don't write wtmp record\n"
39 " --no-wall Don't send wall message before halt/power-off/reboot\n"
40 "\nSee the %s for details.\n",
41 program_invocation_short_name
,
42 arg_action
== ACTION_REBOOT
? " [ARG]" : "",
44 arg_action
== ACTION_REBOOT
? "Reboot" :
45 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 /* called in sysvinit system as last command in shutdown/reboot so this is always forceful */
80 if (utmp_get_runlevel(&runlevel
, NULL
) >= 0)
81 if (IN_SET(runlevel
, '0', '6'))
84 while ((c
= getopt_long(argc
, argv
, "pfwdnih", options
, NULL
)) >= 0)
91 arg_action
= ACTION_HALT
;
95 if (arg_action
!= ACTION_REBOOT
)
96 arg_action
= ACTION_POWEROFF
;
100 arg_action
= ACTION_REBOOT
;
125 /* Compatibility nops */
132 assert_not_reached();
135 if (arg_action
== ACTION_REBOOT
&& (argc
== optind
|| argc
== optind
+ 1)) {
136 r
= update_reboot_parameter_and_warn(argc
== optind
+ 1 ? argv
[optind
] : NULL
, false);
139 } else if (optind
< argc
)
140 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
141 "Too many arguments.");
146 int halt_main(void) {
149 if (arg_force
== 0) {
150 /* always try logind first */
152 r
= logind_schedule_shutdown();
154 r
= logind_check_inhibitors(arg_action
);
158 r
= logind_reboot(arg_action
);
162 if (IN_SET(r
, -EACCES
, -EOPNOTSUPP
, -EINPROGRESS
))
163 /* Requested operation requires auth, is not supported on the local system or already in
166 /* on all other errors, try low-level operation */
168 /* In order to minimize the difference between operation with and without logind, we explicitly
169 * enable non-blocking mode for this, as logind's shutdown operations are always non-blocking. */
173 return start_with_fallback();
176 if (geteuid() != 0) {
177 (void) must_be_root();
183 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
185 r
= utmp_put_shutdown();
187 log_warning_errno(r
, "Failed to write utmp record: %m");
194 r
= halt_now(arg_action
);
195 return log_error_errno(r
, "Failed to %s: %m", action_table
[arg_action
].verb
);