4 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <libsyscommon/dbus-system.h>
23 #include <core/common.h>
36 enum application application;
38 { .name = "reboot", .application = APP_REBOOT, },
39 { .name = "halt", .application = APP_HALT, },
40 { .name = "poweroff", .application = APP_POWEROFF, },
41 { .name = "shutdown", .application = APP_SHUTDOWN, },
44 enum application parse_path(const char *name)
46 const char *base = strrchr(name, '/');
47 base = base ? base + 1 : name;
48 for (size_t i = 0; i < ARRAY_SIZE(apps); ++i) {
49 const char *target = apps[i].name;
51 /* NB: We only check if the prefix matches,
52 * so that we can run "reboot" as, for example "reboot-custom". */
53 if (strncmp(base, target, strlen(target)) == 0)
54 return apps[i].application;
59 /* NB: we are emulating different programs: the "shutdown" program, and the trio of "reboot", "halt"
60 * and "poweroff". These two cases have different option sets, so they need separate parsing methods
61 * and separate usage strings. */
66 SHOW_SHUTDOWN_PARSE_ERROR,
67 SHOW_REBOOT_ET_AL_PARSE_ERROR,
69 SHOW_REBOOT_ET_AL_HELP,
75 const char *extra_option;
77 bool show_sync_warning;
78 bool show_timings_warning;
79 bool show_wall_warning;
80 bool show_wtmp_warning;
83 struct parse_result parse_shutdown(int argc, char **argv) {
88 } action = ACT_POWEROFF;
89 bool will_do_nothing = false;
90 bool show_timings_warning = false;
91 bool show_wall_warning = false;
94 switch (getopt_long(argc, argv, "HPrhkc", (struct option []) {
95 { "help", no_argument, NULL, 0, },
96 { "no-wall", no_argument, NULL, 1, },
97 { "halt", no_argument, NULL, 'H', },
98 { "poweroff", no_argument, NULL, 'P', },
99 { "reboot", no_argument, NULL, 'r', },
100 { NULL, 0, NULL, 0, },
103 switch (argc - optind) {
105 show_wall_warning = true;
106 show_timings_warning = true;
110 show_timings_warning = true;
117 return (struct parse_result) { .operation = SHOW_SHUTDOWN_PARSE_ERROR, };
120 return (struct parse_result) {
121 .operation = will_do_nothing ? DO_NOTHING
122 : action == ACT_REBOOT ? DO_REBOOT
123 : action == ACT_HALT ? DO_EXIT // don't ask difficult questions like "why not DO_HALT"
125 .extra_option = NULL,
126 .show_sync_warning = false,
127 .show_timings_warning = show_timings_warning,
128 .show_wall_warning = show_wall_warning,
129 .show_wtmp_warning = false,
133 return (struct parse_result) { .operation = SHOW_SHUTDOWN_HELP, };
136 show_wall_warning = true;
144 action = ACT_POWEROFF;
152 if (action == ACT_REBOOT)
153 action = ACT_POWEROFF;
157 will_do_nothing = true;
158 show_wall_warning = true;
162 will_do_nothing = true;
163 show_timings_warning = true;
167 return (struct parse_result) { .operation = SHOW_SHUTDOWN_PARSE_ERROR, };
175 struct parse_result parse_reboot_et_al(enum application application, int argc, char **argv) {
181 switch (application) {
191 action = ACT_POWEROFF;
198 bool will_do_nothing = false;
199 bool show_sync_warning = false;
200 bool show_timings_warning = false;
201 bool show_wall_warning = false;
202 bool show_wtmp_warning = false;
203 char *extra_option = NULL;
206 switch (getopt_long(argc, argv, "-pfwdn", (struct option []) {
207 { "help", no_argument, NULL, 0, },
208 /* 1 reserved for options not in -foo format */
209 { "halt", no_argument, NULL, 2, },
210 { "reboot", no_argument, NULL, 3, },
211 { "no-wall", no_argument, NULL, 4, },
212 { "poweroff", no_argument, NULL, 'p', },
213 { "force", no_argument, NULL, 'f', },
214 { "wtmp-only", no_argument, NULL, 'w', },
215 { "no-wtmp", no_argument, NULL, 'd', },
216 { "no-sync", no_argument, NULL, 'n', },
217 { NULL, 0, NULL, 0, },
221 return (struct parse_result) { .operation = SHOW_REBOOT_ET_AL_PARSE_ERROR, };
223 return (struct parse_result) {
224 .operation = will_do_nothing ? DO_NOTHING
225 : action == ACT_REBOOT ? DO_REBOOT
226 : action == ACT_HALT ? DO_EXIT
228 .extra_option = extra_option,
229 .show_sync_warning = show_sync_warning,
230 .show_timings_warning = show_timings_warning,
231 .show_wall_warning = show_wall_warning,
232 .show_wtmp_warning = show_wtmp_warning,
236 return (struct parse_result) { .operation = SHOW_REBOOT_ET_AL_HELP, };
240 return (struct parse_result) { .operation = SHOW_REBOOT_ET_AL_PARSE_ERROR, };
241 extra_option = optarg;
253 show_wall_warning = true;
257 action = ACT_POWEROFF;
261 show_timings_warning = false;
265 will_do_nothing = true;
266 show_wtmp_warning = true;
270 show_wtmp_warning = true;
274 show_sync_warning = true;
278 return (struct parse_result) { .operation = SHOW_REBOOT_ET_AL_PARSE_ERROR, };
286 int call_deviced_poweroff(const char *type, const char *extra_option, const char *message)
288 int result = extra_option
289 ? dbus_handle_method_sync_var(DEVICED_BUS_NAME, DEVICED_PATH_POWEROFF, DEVICED_INTERFACE_POWEROFF, "PowerOffWithOption", g_variant_new("(ss)", type, extra_option), NULL)
290 : dbus_handle_method_sync_var(DEVICED_BUS_NAME, DEVICED_PATH_POWEROFF, DEVICED_INTERFACE_POWEROFF, "PowerOff", g_variant_new("(s)", type), NULL)
293 fprintf(stderr, "Error: %d", result);
297 fprintf(stderr, "%s", message);
303 int main(int argc, char **argv)
305 enum application application = parse_path(argv[0]);
306 struct parse_result parse_result;
307 switch (application) {
309 fprintf(stderr, "This program can only be used as a symlink to 'reboot', 'halt', 'poweroff' or 'shutdown'.\n");
313 parse_result = parse_shutdown(argc, argv);
319 parse_result = parse_reboot_et_al(application, argc, argv);
323 // This shouldn't be needed, but GCC complains otherwise.
328 if (parse_result.show_sync_warning)
329 fprintf(stderr, "Warning: Tizen always syncs, sync options ignored.\n");
330 if (parse_result.show_timings_warning)
331 fprintf(stderr, "Warning: %s doesn't take care of delayed and pending operations on Tizen.\n", argv[0]);
332 if (parse_result.show_wall_warning)
333 fprintf(stderr, "Warning: %s doesn't take care of wall messages on Tizen.\n", argv[0]);
334 if (parse_result.show_wtmp_warning)
335 fprintf(stderr, "Warning: %s doesn't take care of wtmp entries on Tizen.\n", argv[0]);
337 switch (parse_result.operation) {
341 case SHOW_SHUTDOWN_HELP:
342 case SHOW_SHUTDOWN_PARSE_ERROR:
343 fprintf(stderr, "Usage: %s [-HPrh]\n", argv[0]);
344 return parse_result.operation == SHOW_SHUTDOWN_HELP ? EXIT_SUCCESS : EXIT_FAILURE;
346 case SHOW_REBOOT_ET_AL_HELP:
347 case SHOW_REBOOT_ET_AL_PARSE_ERROR:
348 fprintf(stderr, "Usage: %s [-p] [--halt|--poweroff|--reboot] [extra]\n", argv[0]); // FIXME: do we say something about the extras? if yes, do we mention deviced, the configs etc?
349 return parse_result.operation == SHOW_REBOOT_ET_AL_HELP ? EXIT_SUCCESS : EXIT_FAILURE;
352 return call_deviced_poweroff("poweroff", parse_result.extra_option, "Shutting down...\n"); // should be "Powering off" really, "shutting down" is the generic term also encompassing halt/reboot >_>
354 return call_deviced_poweroff("exit", parse_result.extra_option, "Shutting down...\n"); // ditto: exit ultimately boils down to poweroff, too
356 return call_deviced_poweroff("reboot", parse_result.extra_option, "Rebooting...\n");
359 assert(false); // unreachable