1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <getopt.h>
4
5 #include "alloc-util.h"
6 #include "pretty-print.h"
7 #include "systemctl-compat-shutdown.h"
8 #include "systemctl-sysv-compat.h"
9 #include "systemctl.h"
10 #include "terminal-util.h"
11
shutdown_help(void)12 static int shutdown_help(void) {
13 _cleanup_free_ char *link = NULL;
14 int r;
15
16 r = terminal_urlify_man("shutdown", "8", &link);
17 if (r < 0)
18 return log_oom();
19
20 printf("%s [OPTIONS...] [TIME] [WALL...]\n"
21 "\n%sShut down the system.%s\n"
22 "\nOptions:\n"
23 " --help Show this help\n"
24 " -H --halt Halt the machine\n"
25 " -P --poweroff Power-off the machine\n"
26 " -r --reboot Reboot the machine\n"
27 " -h Equivalent to --poweroff, overridden by --halt\n"
28 " -k Don't halt/power-off/reboot, just send warnings\n"
29 " --no-wall Don't send wall message before halt/power-off/reboot\n"
30 " -c Cancel a pending shutdown\n"
31 " --show Show pending shutdown\n"
32 "\nSee the %s for details.\n",
33 program_invocation_short_name,
34 ansi_highlight(),
35 ansi_normal(),
36 link);
37
38 return 0;
39 }
40
shutdown_parse_argv(int argc,char * argv[])41 int shutdown_parse_argv(int argc, char *argv[]) {
42 enum {
43 ARG_HELP = 0x100,
44 ARG_NO_WALL,
45 ARG_SHOW
46 };
47
48 static const struct option options[] = {
49 { "help", no_argument, NULL, ARG_HELP },
50 { "halt", no_argument, NULL, 'H' },
51 { "poweroff", no_argument, NULL, 'P' },
52 { "reboot", no_argument, NULL, 'r' },
53 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
54 { "no-wall", no_argument, NULL, ARG_NO_WALL },
55 { "show", no_argument, NULL, ARG_SHOW },
56 {}
57 };
58
59 char **wall = NULL;
60 int c, r;
61
62 assert(argc >= 0);
63 assert(argv);
64
65 while ((c = getopt_long(argc, argv, "HPrhkKat:fFc", options, NULL)) >= 0)
66 switch (c) {
67
68 case ARG_HELP:
69 return shutdown_help();
70
71 case 'H':
72 arg_action = ACTION_HALT;
73 break;
74
75 case 'P':
76 arg_action = ACTION_POWEROFF;
77 break;
78
79 case 'r':
80 if (kexec_loaded())
81 arg_action = ACTION_KEXEC;
82 else
83 arg_action = ACTION_REBOOT;
84 break;
85
86 case 'K':
87 arg_action = ACTION_KEXEC;
88 break;
89
90 case 'h':
91 if (arg_action != ACTION_HALT)
92 arg_action = ACTION_POWEROFF;
93 break;
94
95 case 'k':
96 arg_dry_run = true;
97 break;
98
99 case ARG_NO_WALL:
100 arg_no_wall = true;
101 break;
102
103 case 'a':
104 case 't': /* Note that we also ignore any passed argument to -t, not just the -t itself */
105 case 'f':
106 case 'F':
107 /* Compatibility nops */
108 break;
109
110 case 'c':
111 arg_action = ACTION_CANCEL_SHUTDOWN;
112 break;
113
114 case ARG_SHOW:
115 arg_action = ACTION_SHOW_SHUTDOWN;
116 break;
117
118 case '?':
119 return -EINVAL;
120
121 default:
122 assert_not_reached();
123 }
124
125 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
126 r = parse_shutdown_time_spec(argv[optind], &arg_when);
127 if (r < 0) {
128 log_error("Failed to parse time specification: %s", argv[optind]);
129 return r;
130 }
131 } else
132 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
133
134 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
135 /* No time argument for shutdown cancel */
136 wall = argv + optind;
137 else if (argc > optind + 1)
138 /* We skip the time argument */
139 wall = argv + optind + 1;
140
141 if (wall) {
142 char **copy = strv_copy(wall);
143 if (!copy)
144 return log_oom();
145 strv_free_and_replace(arg_wall, copy);
146 }
147
148 optind = argc;
149
150 return 1;
151 }
152