153 lines
4.7 KiB
C
153 lines
4.7 KiB
C
/* 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;
|
|
}
|