1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <getopt.h>
4 #include <unistd.h>
5
6 #include "sd-daemon.h"
7
8 #include "alloc-util.h"
9 #include "pretty-print.h"
10 #include "process-util.h"
11 #include "reboot-util.h"
12 #include "systemctl-compat-halt.h"
13 #include "systemctl-compat-telinit.h"
14 #include "systemctl-logind.h"
15 #include "systemctl-start-unit.h"
16 #include "systemctl-util.h"
17 #include "systemctl.h"
18 #include "terminal-util.h"
19 #include "utmp-wtmp.h"
20
halt_help(void)21 static int halt_help(void) {
22 _cleanup_free_ char *link = NULL;
23 int r;
24
25 r = terminal_urlify_man("halt", "8", &link);
26 if (r < 0)
27 return log_oom();
28
29 printf("%s [OPTIONS...]%s\n"
30 "\n%s%s the system.%s\n"
31 "\nOptions:\n"
32 " --help Show this help\n"
33 " --halt Halt the machine\n"
34 " -p --poweroff Switch off the machine\n"
35 " --reboot Reboot the machine\n"
36 " -f --force Force immediate halt/power-off/reboot\n"
37 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
38 " -d --no-wtmp Don't write wtmp record\n"
39 " --no-wall Don't send wall message before halt/power-off/reboot\n"
40 "\nSee the %s for details.\n",
41 program_invocation_short_name,
42 arg_action == ACTION_REBOOT ? " [ARG]" : "",
43 ansi_highlight(),
44 arg_action == ACTION_REBOOT ? "Reboot" :
45 arg_action == ACTION_POWEROFF ? "Power off" :
46 "Halt",
47 ansi_normal(),
48 link);
49
50 return 0;
51 }
52
halt_parse_argv(int argc,char * argv[])53 int halt_parse_argv(int argc, char *argv[]) {
54 enum {
55 ARG_HELP = 0x100,
56 ARG_HALT,
57 ARG_REBOOT,
58 ARG_NO_WALL
59 };
60
61 static const struct option options[] = {
62 { "help", no_argument, NULL, ARG_HELP },
63 { "halt", no_argument, NULL, ARG_HALT },
64 { "poweroff", no_argument, NULL, 'p' },
65 { "reboot", no_argument, NULL, ARG_REBOOT },
66 { "force", no_argument, NULL, 'f' },
67 { "wtmp-only", no_argument, NULL, 'w' },
68 { "no-wtmp", no_argument, NULL, 'd' },
69 { "no-sync", no_argument, NULL, 'n' },
70 { "no-wall", no_argument, NULL, ARG_NO_WALL },
71 {}
72 };
73
74 int c, r, runlevel;
75
76 assert(argc >= 0);
77 assert(argv);
78
79 /* called in sysvinit system as last command in shutdown/reboot so this is always forceful */
80 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
81 if (IN_SET(runlevel, '0', '6'))
82 arg_force = 2;
83
84 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
85 switch (c) {
86
87 case ARG_HELP:
88 return halt_help();
89
90 case ARG_HALT:
91 arg_action = ACTION_HALT;
92 break;
93
94 case 'p':
95 if (arg_action != ACTION_REBOOT)
96 arg_action = ACTION_POWEROFF;
97 break;
98
99 case ARG_REBOOT:
100 arg_action = ACTION_REBOOT;
101 break;
102
103 case 'f':
104 arg_force = 2;
105 break;
106
107 case 'w':
108 arg_dry_run = true;
109 break;
110
111 case 'd':
112 arg_no_wtmp = true;
113 break;
114
115 case 'n':
116 arg_no_sync = true;
117 break;
118
119 case ARG_NO_WALL:
120 arg_no_wall = true;
121 break;
122
123 case 'i':
124 case 'h':
125 /* Compatibility nops */
126 break;
127
128 case '?':
129 return -EINVAL;
130
131 default:
132 assert_not_reached();
133 }
134
135 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
136 r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false);
137 if (r < 0)
138 return r;
139 } else if (optind < argc)
140 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
141 "Too many arguments.");
142
143 return 1;
144 }
145
halt_main(void)146 int halt_main(void) {
147 int r;
148
149 if (arg_force == 0) {
150 /* always try logind first */
151 if (arg_when > 0)
152 r = logind_schedule_shutdown();
153 else {
154 r = logind_check_inhibitors(arg_action);
155 if (r < 0)
156 return r;
157
158 r = logind_reboot(arg_action);
159 }
160 if (r >= 0)
161 return r;
162 if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
163 /* Requested operation requires auth, is not supported on the local system or already in
164 * progress */
165 return r;
166 /* on all other errors, try low-level operation */
167
168 /* In order to minimize the difference between operation with and without logind, we explicitly
169 * enable non-blocking mode for this, as logind's shutdown operations are always non-blocking. */
170 arg_no_block = true;
171
172 if (!arg_dry_run)
173 return start_with_fallback();
174 }
175
176 if (geteuid() != 0) {
177 (void) must_be_root();
178 return -EPERM;
179 }
180
181 if (!arg_no_wtmp) {
182 if (sd_booted() > 0)
183 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
184 else {
185 r = utmp_put_shutdown();
186 if (r < 0)
187 log_warning_errno(r, "Failed to write utmp record: %m");
188 }
189 }
190
191 if (arg_dry_run)
192 return 0;
193
194 r = halt_now(arg_action);
195 return log_error_errno(r, "Failed to %s: %m", action_table[arg_action].verb);
196 }
197