]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl-sysv-compat.c
basic: add RuntimeScope enum
[thirdparty/systemd.git] / src / systemctl / systemctl-sysv-compat.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
daf71ef6
LP
2
3#include <fcntl.h>
4#include <sys/stat.h>
5#include <sys/types.h>
6
7#include "env-util.h"
8#include "fd-util.h"
9#include "initreq.h"
10#include "install.h"
11#include "io-util.h"
12#include "parse-util.h"
13#include "path-util.h"
14#include "process-util.h"
15#include "strv.h"
16#include "systemctl-sysv-compat.h"
17#include "systemctl.h"
18
19int talk_initctl(char rl) {
20#if HAVE_SYSV_COMPAT
254d1313 21 _cleanup_close_ int fd = -EBADF;
5980d463 22 const char *path;
daf71ef6
LP
23 int r;
24
25 /* Try to switch to the specified SysV runlevel. Returns == 0 if the operation does not apply on this
26 * system, and > 0 on success. */
27
28 if (rl == 0)
29 return 0;
30
5980d463
ZJS
31 FOREACH_STRING(_path, "/run/initctl", "/dev/initctl") {
32 path = _path;
daf71ef6 33
5980d463
ZJS
34 fd = open(path, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
35 if (fd < 0 && errno != ENOENT)
36 return log_error_errno(errno, "Failed to open %s: %m", path);
37 if (fd >= 0)
38 break;
daf71ef6 39 }
5980d463
ZJS
40 if (fd < 0)
41 return 0;
daf71ef6 42
5980d463 43 struct init_request request = {
daf71ef6
LP
44 .magic = INIT_MAGIC,
45 .sleeptime = 0,
46 .cmd = INIT_CMD_RUNLVL,
47 .runlevel = rl,
48 };
49
50 r = loop_write(fd, &request, sizeof(request), false);
51 if (r < 0)
5980d463 52 return log_error_errno(r, "Failed to write to %s: %m", path);
daf71ef6
LP
53
54 return 1;
55#else
56 return -EOPNOTSUPP;
57#endif
58}
59
60int parse_shutdown_time_spec(const char *t, usec_t *ret) {
61 assert(t);
62 assert(ret);
63
64 if (streq(t, "now"))
65 *ret = 0;
66 else if (!strchr(t, ':')) {
67 uint64_t u;
68
69 if (safe_atou64(t, &u) < 0)
70 return -EINVAL;
71
72 *ret = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
73 } else {
74 char *e = NULL;
75 long hour, minute;
76 struct tm tm = {};
77 time_t s;
78 usec_t n;
79
80 errno = 0;
81 hour = strtol(t, &e, 10);
82 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
83 return -EINVAL;
84
85 minute = strtol(e+1, &e, 10);
86 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
87 return -EINVAL;
88
89 n = now(CLOCK_REALTIME);
90 s = (time_t) (n / USEC_PER_SEC);
91
92 assert_se(localtime_r(&s, &tm));
93
94 tm.tm_hour = (int) hour;
95 tm.tm_min = (int) minute;
96 tm.tm_sec = 0;
97
98 s = mktime(&tm);
99 assert(s >= 0);
100
101 *ret = (usec_t) s * USEC_PER_SEC;
102
103 while (*ret <= n)
104 *ret += USEC_PER_DAY;
105 }
106
107 return 0;
108}
109
110int enable_sysv_units(const char *verb, char **args) {
111 int r = 0;
112
113#if HAVE_SYSV_COMPAT
114 _cleanup_(lookup_paths_free) LookupPaths paths = {};
115 unsigned f = 0;
43e48a47 116 SysVUnitEnableState enable_state = SYSV_UNIT_NOT_FOUND;
daf71ef6
LP
117
118 /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
119
4870133b 120 if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
daf71ef6
LP
121 return 0;
122
123 if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
124 return 0;
125
126 if (!STR_IN_SET(verb,
127 "enable",
128 "disable",
129 "is-enabled"))
130 return 0;
131
4870133b 132 r = lookup_paths_init_or_warn(&paths, arg_runtime_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
daf71ef6
LP
133 if (r < 0)
134 return r;
135
136 r = 0;
137 while (args[f]) {
138
139 const char *argv[] = {
140 ROOTLIBEXECDIR "/systemd-sysv-install",
141 NULL, /* --root= */
142 NULL, /* verb */
143 NULL, /* service */
144 NULL,
145 };
146
147 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL, *v = NULL;
148 bool found_native = false, found_sysv;
149 const char *name;
150 unsigned c = 1;
151 pid_t pid;
152 int j;
153
154 name = args[f++];
155
156 if (!endswith(name, ".service"))
157 continue;
158
159 if (path_is_absolute(name))
160 continue;
161
4870133b 162 j = unit_file_exists(arg_runtime_scope, &paths, name);
daf71ef6
LP
163 if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
164 return log_error_errno(j, "Failed to look up unit file state: %m");
165 found_native = j != 0;
166
167 /* If we have both a native unit and a SysV script, enable/disable them both (below); for
168 * is-enabled, prefer the native unit */
169 if (found_native && streq(verb, "is-enabled"))
170 continue;
171
172 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
173 if (!p)
174 return log_oom();
175
176 p[strlen(p) - STRLEN(".service")] = 0;
177 found_sysv = access(p, F_OK) >= 0;
178 if (!found_sysv)
179 continue;
180
181 if (!arg_quiet) {
182 if (found_native)
183 log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
184 else
185 log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
186 }
187
188 if (!isempty(arg_root)) {
189 q = strjoin("--root=", arg_root);
190 if (!q)
191 return log_oom();
192
193 argv[c++] = q;
194 }
195
196 /* Let's copy the verb, since it's still pointing directly into the original argv[] array we
197 * got passed, but safe_fork() is likely going to rewrite that for the new child */
198 v = strdup(verb);
199 if (!v)
200 return log_oom();
201
202 argv[c++] = v;
203 argv[c++] = basename(p);
204 argv[c] = NULL;
205
206 l = strv_join((char**)argv, " ");
207 if (!l)
208 return log_oom();
209
210 if (!arg_quiet)
211 log_info("Executing: %s", l);
212
213 j = safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
214 if (j < 0)
215 return j;
216 if (j == 0) {
217 /* Child */
218 execv(argv[0], (char**) argv);
219 log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
220 _exit(EXIT_FAILURE);
221 }
222
223 j = wait_for_terminate_and_check("sysv-install", pid, WAIT_LOG_ABNORMAL);
224 if (j < 0)
225 return j;
226 if (streq(verb, "is-enabled")) {
227 if (j == EXIT_SUCCESS) {
228 if (!arg_quiet)
229 puts("enabled");
43e48a47 230 enable_state = SYSV_UNIT_ENABLED;
daf71ef6
LP
231 } else {
232 if (!arg_quiet)
233 puts("disabled");
43e48a47
MY
234 if (enable_state != SYSV_UNIT_ENABLED)
235 enable_state = SYSV_UNIT_DISABLED;
daf71ef6
LP
236 }
237
238 } else if (j != EXIT_SUCCESS)
239 return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
240
241 if (found_native)
242 continue;
243
244 /* Remove this entry, so that we don't try enabling it as native unit */
245 assert(f > 0);
246 f--;
247 assert(args[f] == name);
248 strv_remove(args + f, name);
249 }
250
43e48a47
MY
251 if (streq(verb, "is-enabled"))
252 return enable_state;
daf71ef6
LP
253#endif
254 return r;
255}
256
257int action_to_runlevel(void) {
258#if HAVE_SYSV_COMPAT
259 static const char table[_ACTION_MAX] = {
260 [ACTION_HALT] = '0',
261 [ACTION_POWEROFF] = '0',
262 [ACTION_REBOOT] = '6',
263 [ACTION_RUNLEVEL2] = '2',
264 [ACTION_RUNLEVEL3] = '3',
265 [ACTION_RUNLEVEL4] = '4',
266 [ACTION_RUNLEVEL5] = '5',
267 [ACTION_RESCUE] = '1'
268 };
269
270 assert(arg_action >= 0 && arg_action < _ACTION_MAX);
271 return table[arg_action];
272#else
273 return -EOPNOTSUPP;
274#endif
275}