Systemd/src/systemctl/systemctl-compat-halt.c
Lennart Poettering daf71ef61c systemctl: split up humungous systemctl.c file
This is just some refactoring: shifting around of code, not change in
codeflow.

This splits up the way too huge systemctl.c in multiple more easily
digestable files. It roughly follows the rule that each family of verbs
gets its own .c/.h file pair, and so do all the compat executable names
we support. Plus three extra files for sysv compat (which existed before
already, but I renamed slightly, to get the systemctl- prefix lik
everything else), a -util file with generic stuff everything uses, and a
-logind file with everything that talks directly to logind instead of
PID1.

systemctl is still a bit too complex for my taste, but I think this way
itc omes in a more digestable bits at least.

No change of behaviour, just reshuffling of some code.
2020-10-07 23:12:15 +02:00

203 lines
6.7 KiB
C

/* SPDX-License-Identifier: LGPL-2.1+ */
#include <getopt.h>
#include <unistd.h>
#include "sd-daemon.h"
#include "alloc-util.h"
#include "pretty-print.h"
#include "process-util.h"
#include "reboot-util.h"
#include "systemctl-compat-halt.h"
#include "systemctl-compat-telinit.h"
#include "systemctl-logind.h"
#include "systemctl-util.h"
#include "systemctl.h"
#include "terminal-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();
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"
"\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()
, 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, runlevel;
assert(argc >= 0);
assert(argv);
if (utmp_get_runlevel(&runlevel, NULL) >= 0)
if (IN_SET(runlevel, '0', '6'))
arg_force = 2;
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("Unhandled option");
}
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;
r = logind_check_inhibitors(arg_action);
if (r < 0)
return r;
/* Delayed shutdown requested, and was successful */
if (arg_when > 0 && logind_schedule_shutdown() == 0)
return 0;
/* No delay, or logind failed or is not at all available */
if (geteuid() != 0) {
if (arg_dry_run || arg_force > 0) {
(void) must_be_root();
return -EPERM;
}
/* Try logind if we are a normal user and no special mode applies. Maybe polkit allows us to
* shutdown the machine. */
if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
r = logind_reboot(arg_action);
if (r >= 0)
return r;
if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
/* Requested operation 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 && !arg_force)
return start_with_fallback();
assert(geteuid() == 0);
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 reboot: %m");
}