/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include #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) { char **copy = strv_copy(wall); if (!copy) return log_oom(); strv_free_and_replace(arg_wall, copy); } optind = argc; return 1; }