144 lines
4.6 KiB
C
144 lines
4.6 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
|
|
#include <getopt.h>
|
|
|
|
#include "alloc-util.h"
|
|
#include "pretty-print.h"
|
|
#include "systemctl-compat-shutdown.h"
|
|
#include "systemctl-sysv-compat.h"
|
|
#include "systemctl.h"
|
|
#include "terminal-util.h"
|
|
|
|
static int shutdown_help(void) {
|
|
_cleanup_free_ char *link = NULL;
|
|
int r;
|
|
|
|
r = terminal_urlify_man("shutdown", "8", &link);
|
|
if (r < 0)
|
|
return log_oom();
|
|
|
|
printf("%s [OPTIONS...] [TIME] [WALL...]\n"
|
|
"\n%sShut down the system.%s\n"
|
|
"\nOptions:\n"
|
|
" --help Show this help\n"
|
|
" -H --halt Halt the machine\n"
|
|
" -P --poweroff Power-off the machine\n"
|
|
" -r --reboot Reboot the machine\n"
|
|
" -h Equivalent to --poweroff, overridden by --halt\n"
|
|
" -k Don't halt/power-off/reboot, just send warnings\n"
|
|
" --no-wall Don't send wall message before halt/power-off/reboot\n"
|
|
" -c Cancel a pending shutdown\n"
|
|
"\nSee the %s for details.\n"
|
|
, program_invocation_short_name
|
|
, ansi_highlight(), ansi_normal()
|
|
, link
|
|
);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int shutdown_parse_argv(int argc, char *argv[]) {
|
|
enum {
|
|
ARG_HELP = 0x100,
|
|
ARG_NO_WALL
|
|
};
|
|
|
|
static const struct option options[] = {
|
|
{ "help", no_argument, NULL, ARG_HELP },
|
|
{ "halt", no_argument, NULL, 'H' },
|
|
{ "poweroff", no_argument, NULL, 'P' },
|
|
{ "reboot", no_argument, NULL, 'r' },
|
|
{ "kexec", no_argument, NULL, 'K' }, /* not documented extension */
|
|
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
|
|
{}
|
|
};
|
|
|
|
char **wall = NULL;
|
|
int c, r;
|
|
|
|
assert(argc >= 0);
|
|
assert(argv);
|
|
|
|
while ((c = getopt_long(argc, argv, "HPrhkKat:fFc", options, NULL)) >= 0)
|
|
switch (c) {
|
|
|
|
case ARG_HELP:
|
|
return shutdown_help();
|
|
|
|
case 'H':
|
|
arg_action = ACTION_HALT;
|
|
break;
|
|
|
|
case 'P':
|
|
arg_action = ACTION_POWEROFF;
|
|
break;
|
|
|
|
case 'r':
|
|
if (kexec_loaded())
|
|
arg_action = ACTION_KEXEC;
|
|
else
|
|
arg_action = ACTION_REBOOT;
|
|
break;
|
|
|
|
case 'K':
|
|
arg_action = ACTION_KEXEC;
|
|
break;
|
|
|
|
case 'h':
|
|
if (arg_action != ACTION_HALT)
|
|
arg_action = ACTION_POWEROFF;
|
|
break;
|
|
|
|
case 'k':
|
|
arg_dry_run = true;
|
|
break;
|
|
|
|
case ARG_NO_WALL:
|
|
arg_no_wall = true;
|
|
break;
|
|
|
|
case 'a':
|
|
case 't': /* Note that we also ignore any passed argument to -t, not just the -t itself */
|
|
case 'f':
|
|
case 'F':
|
|
/* Compatibility nops */
|
|
break;
|
|
|
|
case 'c':
|
|
arg_action = ACTION_CANCEL_SHUTDOWN;
|
|
break;
|
|
|
|
case '?':
|
|
return -EINVAL;
|
|
|
|
default:
|
|
assert_not_reached("Unhandled option");
|
|
}
|
|
|
|
if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
|
|
r = parse_shutdown_time_spec(argv[optind], &arg_when);
|
|
if (r < 0) {
|
|
log_error("Failed to parse time specification: %s", argv[optind]);
|
|
return r;
|
|
}
|
|
} else
|
|
arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
|
|
|
|
if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
|
|
/* No time argument for shutdown cancel */
|
|
wall = argv + optind;
|
|
else if (argc > optind + 1)
|
|
/* We skip the time argument */
|
|
wall = argv + optind + 1;
|
|
|
|
if (wall) {
|
|
arg_wall = strv_copy(wall);
|
|
if (!arg_wall)
|
|
return log_oom();
|
|
}
|
|
|
|
optind = argc;
|
|
|
|
return 1;
|
|
}
|