1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <getopt.h>
4 #include <unistd.h>
5
6 #include "alloc-util.h"
7 #include "pretty-print.h"
8 #include "rlimit-util.h"
9 #include "systemctl-compat-telinit.h"
10 #include "systemctl-daemon-reload.h"
11 #include "systemctl-start-unit.h"
12 #include "systemctl-sysv-compat.h"
13 #include "systemctl.h"
14 #include "terminal-util.h"
15
telinit_help(void)16 static int telinit_help(void) {
17 _cleanup_free_ char *link = NULL;
18 int r;
19
20 r = terminal_urlify_man("telinit", "8", &link);
21 if (r < 0)
22 return log_oom();
23
24 printf("%s [OPTIONS...] COMMAND\n\n"
25 "%sSend control commands to the init daemon.%s\n"
26 "\nCommands:\n"
27 " 0 Power-off the machine\n"
28 " 6 Reboot the machine\n"
29 " 2, 3, 4, 5 Start runlevelX.target unit\n"
30 " 1, s, S Enter rescue mode\n"
31 " q, Q Reload init daemon configuration\n"
32 " u, U Reexecute init daemon\n"
33 "\nOptions:\n"
34 " --help Show this help\n"
35 " --no-wall Don't send wall message before halt/power-off/reboot\n"
36 "\nSee the %s for details.\n",
37 program_invocation_short_name,
38 ansi_highlight(),
39 ansi_normal(),
40 link);
41
42 return 0;
43 }
44
telinit_parse_argv(int argc,char * argv[])45 int telinit_parse_argv(int argc, char *argv[]) {
46 enum {
47 ARG_HELP = 0x100,
48 ARG_NO_WALL
49 };
50
51 static const struct option options[] = {
52 { "help", no_argument, NULL, ARG_HELP },
53 { "no-wall", no_argument, NULL, ARG_NO_WALL },
54 {}
55 };
56
57 static const struct {
58 char from;
59 enum action to;
60 } table[] = {
61 { '0', ACTION_POWEROFF },
62 { '6', ACTION_REBOOT },
63 { '1', ACTION_RESCUE },
64 { '2', ACTION_RUNLEVEL2 },
65 { '3', ACTION_RUNLEVEL3 },
66 { '4', ACTION_RUNLEVEL4 },
67 { '5', ACTION_RUNLEVEL5 },
68 { 's', ACTION_RESCUE },
69 { 'S', ACTION_RESCUE },
70 { 'q', ACTION_RELOAD },
71 { 'Q', ACTION_RELOAD },
72 { 'u', ACTION_REEXEC },
73 { 'U', ACTION_REEXEC }
74 };
75
76 unsigned i;
77 int c;
78
79 assert(argc >= 0);
80 assert(argv);
81
82 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
83 switch (c) {
84
85 case ARG_HELP:
86 return telinit_help();
87
88 case ARG_NO_WALL:
89 arg_no_wall = true;
90 break;
91
92 case '?':
93 return -EINVAL;
94
95 default:
96 assert_not_reached();
97 }
98
99 if (optind >= argc)
100 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
101 "%s: required argument missing.",
102 program_invocation_short_name);
103
104 if (optind + 1 < argc)
105 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
106 "Too many arguments.");
107
108 if (strlen(argv[optind]) != 1)
109 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
110 "Expected single character argument.");
111
112 for (i = 0; i < ELEMENTSOF(table); i++)
113 if (table[i].from == argv[optind][0])
114 break;
115
116 if (i >= ELEMENTSOF(table))
117 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
118 "Unknown command '%s'.", argv[optind]);
119
120 arg_action = table[i].to;
121
122 optind++;
123
124 return 1;
125 }
126
start_with_fallback(void)127 int start_with_fallback(void) {
128 int r;
129
130 /* First, try systemd via D-Bus. */
131 r = verb_start(0, NULL, NULL);
132 if (r == 0)
133 return 0;
134
135 #if HAVE_SYSV_COMPAT
136 /* Nothing else worked, so let's try /dev/initctl */
137 if (talk_initctl(action_to_runlevel()) > 0)
138 return 0;
139 #endif
140
141 return log_error_errno(r, "Failed to talk to init daemon: %m");
142 }
143
reload_with_fallback(void)144 int reload_with_fallback(void) {
145
146 assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
147
148 /* First, try systemd via D-Bus */
149 if (daemon_reload(arg_action, /* graceful= */ true) > 0)
150 return 0;
151
152 /* That didn't work, so let's try signals */
153 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
154 return log_error_errno(errno, "kill() failed: %m");
155
156 return 0;
157 }
158
exec_telinit(char * argv[])159 int exec_telinit(char *argv[]) {
160 (void) rlimit_nofile_safe();
161 (void) execv(TELINIT, argv);
162
163 return log_error_errno(SYNTHETIC_ERRNO(EIO),
164 "Couldn't find an alternative telinit implementation to spawn.");
165 }
166