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