Files
systemd/src/systemctl/systemctl-compat-halt.c
T
Yu Watanabe 8ba48d4bf8 core,initctl,systemctl: kill /dev/initctl support
This also kills support for controlling system state through
/sbin/init, initctl, and telinit.
2025-07-13 05:38:14 +09:00

196 lines
6.9 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include "sd-daemon.h"
#include "alloc-util.h"
#include "log.h"
#include "pretty-print.h"
#include "process-util.h"
#include "reboot-util.h"
#include "systemctl.h"
#include "systemctl-compat-halt.h"
#include "systemctl-logind.h"
#include "systemctl-start-unit.h"
#include "systemctl-util.h"
#include "utmp-wtmp.h"
static int halt_help(void) {
_cleanup_free_ char *link = NULL;
int r;
r = terminal_urlify_man("halt", "8", &link);
if (r < 0)
return log_oom();
/* Note: if you are tempted to add new command line switches here, please do not. Let this
* compatibility command rest in peace. Its interface is not even owned by us as much as it is by
* sysvinit. If you add something new, add it to "systemctl halt", "systemctl reboot", "systemctl
* poweroff" instead. */
printf("%s [OPTIONS...]%s\n"
"\n%s%s the system.%s\n"
"\nOptions:\n"
" --help Show this help\n"
" --halt Halt the machine\n"
" -p --poweroff Switch off the machine\n"
" --reboot Reboot the machine\n"
" -f --force Force immediate halt/power-off/reboot\n"
" -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
" -d --no-wtmp Don't write wtmp record\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n"
"\n%sThis is a compatibility interface, please use the more powerful 'systemctl %s' command instead.%s\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
arg_action == ACTION_REBOOT ? " [ARG]" : "",
ansi_highlight(), arg_action == ACTION_REBOOT ? "Reboot" :
arg_action == ACTION_POWEROFF ? "Power off" :
"Halt", ansi_normal(),
ansi_highlight_red(), arg_action == ACTION_REBOOT ? "reboot" :
arg_action == ACTION_POWEROFF ? "poweroff" :
"halt", ansi_normal(),
link);
return 0;
}
int halt_parse_argv(int argc, char *argv[]) {
enum {
ARG_HELP = 0x100,
ARG_HALT,
ARG_REBOOT,
ARG_NO_WALL
};
static const struct option options[] = {
{ "help", no_argument, NULL, ARG_HELP },
{ "halt", no_argument, NULL, ARG_HALT },
{ "poweroff", no_argument, NULL, 'p' },
{ "reboot", no_argument, NULL, ARG_REBOOT },
{ "force", no_argument, NULL, 'f' },
{ "wtmp-only", no_argument, NULL, 'w' },
{ "no-wtmp", no_argument, NULL, 'd' },
{ "no-sync", no_argument, NULL, 'n' },
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
switch (c) {
case ARG_HELP:
return halt_help();
case ARG_HALT:
arg_action = ACTION_HALT;
break;
case 'p':
if (arg_action != ACTION_REBOOT)
arg_action = ACTION_POWEROFF;
break;
case ARG_REBOOT:
arg_action = ACTION_REBOOT;
break;
case 'f':
arg_force = 2;
break;
case 'w':
arg_dry_run = true;
break;
case 'd':
arg_no_wtmp = true;
break;
case 'n':
arg_no_sync = true;
break;
case ARG_NO_WALL:
arg_no_wall = true;
break;
case 'i':
case 'h':
/* Compatibility nops */
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false);
if (r < 0)
return r;
} else if (optind < argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Too many arguments.");
return 1;
}
int halt_main(void) {
int r;
if (arg_force == 0) {
/* always try logind first */
if (arg_when > 0)
r = logind_schedule_shutdown(arg_action);
else {
r = logind_check_inhibitors(arg_action);
if (r < 0)
return r;
r = logind_reboot(arg_action);
}
if (r >= 0)
return r;
if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
/* Requested operation requires auth, is not supported on the local system or already in
* progress */
return r;
/* on all other errors, try low-level operation */
/* In order to minimize the difference between operation with and without logind, we explicitly
* enable non-blocking mode for this, as logind's shutdown operations are always non-blocking. */
arg_no_block = true;
if (!arg_dry_run)
return verb_start(0, NULL, NULL);
}
r = must_be_root();
if (r < 0)
return r;
if (!arg_no_wtmp) {
if (sd_booted() > 0)
log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
else {
r = utmp_put_shutdown();
if (r < 0)
log_warning_errno(r, "Failed to write utmp record: %m");
}
}
if (arg_dry_run)
return 0;
r = halt_now(arg_action);
return log_error_errno(r, "Failed to %s: %m", action_table[arg_action].verb);
}