| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| |
| #include <getopt.h> |
| |
| #include "alloc-util.h" |
| #include "pretty-print.h" |
| #include "systemctl-compat-telinit.h" |
| #include "systemctl-daemon-reload.h" |
| #include "systemctl-start-unit.h" |
| #include "systemctl-sysv-compat.h" |
| #include "systemctl.h" |
| #include "terminal-util.h" |
| |
| static int telinit_help(void) { |
| _cleanup_free_ char *link = NULL; |
| int r; |
| |
| r = terminal_urlify_man("telinit", "8", &link); |
| if (r < 0) |
| return log_oom(); |
| |
| printf("%s [OPTIONS...] COMMAND\n\n" |
| "%sSend control commands to the init daemon.%s\n" |
| "\nCommands:\n" |
| " 0 Power-off the machine\n" |
| " 6 Reboot the machine\n" |
| " 2, 3, 4, 5 Start runlevelX.target unit\n" |
| " 1, s, S Enter rescue mode\n" |
| " q, Q Reload init daemon configuration\n" |
| " u, U Reexecute init daemon\n" |
| "\nOptions:\n" |
| " --help Show this help\n" |
| " --no-wall Don't send wall message before halt/power-off/reboot\n" |
| "\nSee the %s for details.\n" |
| , program_invocation_short_name |
| , ansi_highlight(), ansi_normal() |
| , link |
| ); |
| |
| return 0; |
| } |
| |
| int telinit_parse_argv(int argc, char *argv[]) { |
| enum { |
| ARG_HELP = 0x100, |
| ARG_NO_WALL |
| }; |
| |
| static const struct option options[] = { |
| { "help", no_argument, NULL, ARG_HELP }, |
| { "no-wall", no_argument, NULL, ARG_NO_WALL }, |
| {} |
| }; |
| |
| static const struct { |
| char from; |
| enum action to; |
| } table[] = { |
| { '0', ACTION_POWEROFF }, |
| { '6', ACTION_REBOOT }, |
| { '1', ACTION_RESCUE }, |
| { '2', ACTION_RUNLEVEL2 }, |
| { '3', ACTION_RUNLEVEL3 }, |
| { '4', ACTION_RUNLEVEL4 }, |
| { '5', ACTION_RUNLEVEL5 }, |
| { 's', ACTION_RESCUE }, |
| { 'S', ACTION_RESCUE }, |
| { 'q', ACTION_RELOAD }, |
| { 'Q', ACTION_RELOAD }, |
| { 'u', ACTION_REEXEC }, |
| { 'U', ACTION_REEXEC } |
| }; |
| |
| unsigned i; |
| int c; |
| |
| assert(argc >= 0); |
| assert(argv); |
| |
| while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) |
| switch (c) { |
| |
| case ARG_HELP: |
| return telinit_help(); |
| |
| case ARG_NO_WALL: |
| arg_no_wall = true; |
| break; |
| |
| case '?': |
| return -EINVAL; |
| |
| default: |
| assert_not_reached("Unhandled option"); |
| } |
| |
| if (optind >= argc) |
| return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
| "%s: required argument missing.", |
| program_invocation_short_name); |
| |
| if (optind + 1 < argc) |
| return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
| "Too many arguments."); |
| |
| if (strlen(argv[optind]) != 1) |
| return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
| "Expected single character argument."); |
| |
| for (i = 0; i < ELEMENTSOF(table); i++) |
| if (table[i].from == argv[optind][0]) |
| break; |
| |
| if (i >= ELEMENTSOF(table)) |
| return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
| "Unknown command '%s'.", argv[optind]); |
| |
| arg_action = table[i].to; |
| |
| optind++; |
| |
| return 1; |
| } |
| |
| int start_with_fallback(void) { |
| /* First, try systemd via D-Bus. */ |
| if (start_unit(0, NULL, NULL) == 0) |
| return 0; |
| |
| #if HAVE_SYSV_COMPAT |
| /* Nothing else worked, so let's try /dev/initctl */ |
| if (talk_initctl(action_to_runlevel()) > 0) |
| return 0; |
| #endif |
| |
| return log_error_errno(SYNTHETIC_ERRNO(EIO), |
| "Failed to talk to init daemon."); |
| } |
| |
| int reload_with_fallback(void) { |
| /* First, try systemd via D-Bus. */ |
| if (daemon_reload(0, NULL, NULL) >= 0) |
| return 0; |
| |
| /* Nothing else worked, so let's try signals */ |
| assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC)); |
| |
| if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) |
| return log_error_errno(errno, "kill() failed: %m"); |
| |
| return 0; |
| } |