File: | build-scan/../src/sysv-generator/sysv-generator.c |
Warning: | line 405, column 21 Null pointer passed to 1st parameter expecting 'nonnull' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | ||||
2 | |||||
3 | #include <errno(*__errno_location ()).h> | ||||
4 | #include <stdio.h> | ||||
5 | #include <unistd.h> | ||||
6 | |||||
7 | #include "alloc-util.h" | ||||
8 | #include "dirent-util.h" | ||||
9 | #include "exit-status.h" | ||||
10 | #include "fd-util.h" | ||||
11 | #include "fileio.h" | ||||
12 | #include "generator.h" | ||||
13 | #include "hashmap.h" | ||||
14 | #include "hexdecoct.h" | ||||
15 | #include "install.h" | ||||
16 | #include "log.h" | ||||
17 | #include "mkdir.h" | ||||
18 | #include "path-lookup.h" | ||||
19 | #include "path-util.h" | ||||
20 | #include "set.h" | ||||
21 | #include "special.h" | ||||
22 | #include "specifier.h" | ||||
23 | #include "stat-util.h" | ||||
24 | #include "string-util.h" | ||||
25 | #include "strv.h" | ||||
26 | #include "unit-name.h" | ||||
27 | #include "util.h" | ||||
28 | |||||
29 | static const struct { | ||||
30 | const char *path; | ||||
31 | const char *target; | ||||
32 | } rcnd_table[] = { | ||||
33 | /* Standard SysV runlevels for start-up */ | ||||
34 | { "rc1.d", SPECIAL_RESCUE_TARGET"rescue.target" }, | ||||
35 | { "rc2.d", SPECIAL_MULTI_USER_TARGET"multi-user.target" }, | ||||
36 | { "rc3.d", SPECIAL_MULTI_USER_TARGET"multi-user.target" }, | ||||
37 | { "rc4.d", SPECIAL_MULTI_USER_TARGET"multi-user.target" }, | ||||
38 | { "rc5.d", SPECIAL_GRAPHICAL_TARGET"graphical.target" }, | ||||
39 | |||||
40 | /* We ignore the SysV runlevels for shutdown here, as SysV services get default dependencies anyway, and that | ||||
41 | * means they are shut down anyway at system power off if running. */ | ||||
42 | }; | ||||
43 | |||||
44 | static const char *arg_dest = "/tmp"; | ||||
45 | |||||
46 | typedef struct SysvStub { | ||||
47 | char *name; | ||||
48 | char *path; | ||||
49 | char *description; | ||||
50 | int sysv_start_priority; | ||||
51 | char *pid_file; | ||||
52 | char **before; | ||||
53 | char **after; | ||||
54 | char **wants; | ||||
55 | char **wanted_by; | ||||
56 | bool_Bool has_lsb; | ||||
57 | bool_Bool reload; | ||||
58 | bool_Bool loaded; | ||||
59 | } SysvStub; | ||||
60 | |||||
61 | static void free_sysvstub(SysvStub *s) { | ||||
62 | if (!s) | ||||
63 | return; | ||||
64 | |||||
65 | free(s->name); | ||||
66 | free(s->path); | ||||
67 | free(s->description); | ||||
68 | free(s->pid_file); | ||||
69 | strv_free(s->before); | ||||
70 | strv_free(s->after); | ||||
71 | strv_free(s->wants); | ||||
72 | strv_free(s->wanted_by); | ||||
73 | free(s); | ||||
74 | } | ||||
75 | |||||
76 | DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, free_sysvstub)static inline void free_sysvstubp(SysvStub* *p) { if (*p) free_sysvstub (*p); }; | ||||
77 | |||||
78 | static void free_sysvstub_hashmapp(Hashmap **h) { | ||||
79 | hashmap_free_with_destructor(*h, free_sysvstub)({ ({ void *_item; while ((_item = hashmap_steal_first(*h))) free_sysvstub (_item); }); hashmap_free(*h); }); | ||||
80 | } | ||||
81 | |||||
82 | static int add_alias(const char *service, const char *alias) { | ||||
83 | const char *link; | ||||
84 | int r; | ||||
85 | |||||
86 | assert(service)do { if ((__builtin_expect(!!(!(service)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("service"), "../src/sysv-generator/sysv-generator.c" , 86, __PRETTY_FUNCTION__); } while (0); | ||||
87 | assert(alias)do { if ((__builtin_expect(!!(!(alias)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("alias"), "../src/sysv-generator/sysv-generator.c" , 87, __PRETTY_FUNCTION__); } while (0); | ||||
88 | |||||
89 | link = strjoina(arg_dest, "/", alias)({ const char *_appendees_[] = { arg_dest, "/", alias }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | ||||
90 | |||||
91 | r = symlink(service, link); | ||||
92 | if (r < 0) { | ||||
93 | if (errno(*__errno_location ()) == EEXIST17) | ||||
94 | return 0; | ||||
95 | |||||
96 | return -errno(*__errno_location ()); | ||||
97 | } | ||||
98 | |||||
99 | return 1; | ||||
100 | } | ||||
101 | |||||
102 | static int generate_unit_file(SysvStub *s) { | ||||
103 | _cleanup_free___attribute__((cleanup(freep))) char *path_escaped = NULL((void*)0); | ||||
104 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | ||||
105 | const char *unit; | ||||
106 | char **p; | ||||
107 | int r; | ||||
108 | |||||
109 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/sysv-generator/sysv-generator.c" , 109, __PRETTY_FUNCTION__); } while (0); | ||||
110 | |||||
111 | if (!s->loaded) | ||||
112 | return 0; | ||||
113 | |||||
114 | path_escaped = specifier_escape(s->path); | ||||
115 | if (!path_escaped) | ||||
116 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 116, __func__); | ||||
117 | |||||
118 | unit = strjoina(arg_dest, "/", s->name)({ const char *_appendees_[] = { arg_dest, "/", s->name }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | ||||
119 | |||||
120 | /* We might already have a symlink with the same name from a Provides:, | ||||
121 | * or from backup files like /etc/init.d/foo.bak. Real scripts always win, | ||||
122 | * so remove an existing link */ | ||||
123 | if (is_symlink(unit) > 0) { | ||||
124 | log_warning("Overwriting existing symlink %s with real service.", unit)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 124, __func__, "Overwriting existing symlink %s with real service." , unit) : -abs(_e); }); | ||||
125 | (void) unlink(unit); | ||||
126 | } | ||||
127 | |||||
128 | f = fopen(unit, "wxe"); | ||||
129 | if (!f) | ||||
130 | return log_error_errno(errno, "Failed to create unit file %s: %m", unit)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/sysv-generator/sysv-generator.c" , 130, __func__, "Failed to create unit file %s: %m", unit) : -abs(_e); }); | ||||
131 | |||||
132 | fprintf(f, | ||||
133 | "# Automatically generated by systemd-sysv-generator\n\n" | ||||
134 | "[Unit]\n" | ||||
135 | "Documentation=man:systemd-sysv-generator(8)\n" | ||||
136 | "SourcePath=%s\n", | ||||
137 | path_escaped); | ||||
138 | |||||
139 | if (s->description) { | ||||
140 | _cleanup_free___attribute__((cleanup(freep))) char *t; | ||||
141 | |||||
142 | t = specifier_escape(s->description); | ||||
143 | if (!t) | ||||
144 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 144, __func__); | ||||
145 | |||||
146 | fprintf(f, "Description=%s\n", t); | ||||
147 | } | ||||
148 | |||||
149 | STRV_FOREACH(p, s->before)for ((p) = (s->before); (p) && *(p); (p)++) | ||||
150 | fprintf(f, "Before=%s\n", *p); | ||||
151 | STRV_FOREACH(p, s->after)for ((p) = (s->after); (p) && *(p); (p)++) | ||||
152 | fprintf(f, "After=%s\n", *p); | ||||
153 | STRV_FOREACH(p, s->wants)for ((p) = (s->wants); (p) && *(p); (p)++) | ||||
154 | fprintf(f, "Wants=%s\n", *p); | ||||
155 | |||||
156 | fprintf(f, | ||||
157 | "\n[Service]\n" | ||||
158 | "Type=forking\n" | ||||
159 | "Restart=no\n" | ||||
160 | "TimeoutSec=5min\n" | ||||
161 | "IgnoreSIGPIPE=no\n" | ||||
162 | "KillMode=process\n" | ||||
163 | "GuessMainPID=no\n" | ||||
164 | "RemainAfterExit=%s\n", | ||||
165 | yes_no(!s->pid_file)); | ||||
166 | |||||
167 | if (s->pid_file) { | ||||
168 | _cleanup_free___attribute__((cleanup(freep))) char *t; | ||||
169 | |||||
170 | t = specifier_escape(s->pid_file); | ||||
171 | if (!t) | ||||
172 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 172, __func__); | ||||
173 | |||||
174 | fprintf(f, "PIDFile=%s\n", t); | ||||
175 | } | ||||
176 | |||||
177 | /* Consider two special LSB exit codes a clean exit */ | ||||
178 | if (s->has_lsb) | ||||
179 | fprintf(f, | ||||
180 | "SuccessExitStatus=%i %i\n", | ||||
181 | EXIT_NOTINSTALLED, | ||||
182 | EXIT_NOTCONFIGURED); | ||||
183 | |||||
184 | fprintf(f, | ||||
185 | "ExecStart=%s start\n" | ||||
186 | "ExecStop=%s stop\n", | ||||
187 | path_escaped, path_escaped); | ||||
188 | |||||
189 | if (s->reload) | ||||
190 | fprintf(f, "ExecReload=%s reload\n", path_escaped); | ||||
191 | |||||
192 | r = fflush_and_check(f); | ||||
193 | if (r < 0) | ||||
194 | return log_error_errno(r, "Failed to write unit %s: %m", unit)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 194, __func__, "Failed to write unit %s: %m" , unit) : -abs(_e); }); | ||||
195 | |||||
196 | STRV_FOREACH(p, s->wanted_by)for ((p) = (s->wanted_by); (p) && *(p); (p)++) | ||||
197 | (void) generator_add_symlink(arg_dest, *p, "wants", s->name); | ||||
198 | |||||
199 | return 1; | ||||
200 | } | ||||
201 | |||||
202 | static bool_Bool usage_contains_reload(const char *line) { | ||||
203 | return (strcasestr(line, "{reload|") || | ||||
204 | strcasestr(line, "{reload}") || | ||||
205 | strcasestr(line, "{reload\"") || | ||||
206 | strcasestr(line, "|reload|") || | ||||
207 | strcasestr(line, "|reload}") || | ||||
208 | strcasestr(line, "|reload\"")); | ||||
209 | } | ||||
210 | |||||
211 | static char *sysv_translate_name(const char *name) { | ||||
212 | _cleanup_free___attribute__((cleanup(freep))) char *c = NULL((void*)0); | ||||
213 | char *res; | ||||
214 | |||||
215 | c = strdup(name); | ||||
216 | if (!c) | ||||
217 | return NULL((void*)0); | ||||
218 | |||||
219 | res = endswith(c, ".sh"); | ||||
220 | if (res) | ||||
221 | *res = 0; | ||||
222 | |||||
223 | if (unit_name_mangle(c, 0, &res) < 0) | ||||
224 | return NULL((void*)0); | ||||
225 | |||||
226 | return res; | ||||
227 | } | ||||
228 | |||||
229 | static int sysv_translate_facility(SysvStub *s, unsigned line, const char *name, char **ret) { | ||||
230 | |||||
231 | /* We silently ignore the $ prefix here. According to the LSB | ||||
232 | * spec it simply indicates whether something is a | ||||
233 | * standardized name or a distribution-specific one. Since we | ||||
234 | * just follow what already exists and do not introduce new | ||||
235 | * uses or names we don't care who introduced a new name. */ | ||||
236 | |||||
237 | static const char * const table[] = { | ||||
238 | /* LSB defined facilities */ | ||||
239 | "local_fs", NULL((void*)0), | ||||
240 | "network", SPECIAL_NETWORK_ONLINE_TARGET"network-online.target", | ||||
241 | "named", SPECIAL_NSS_LOOKUP_TARGET"nss-lookup.target", | ||||
242 | "portmap", SPECIAL_RPCBIND_TARGET"rpcbind.target", | ||||
243 | "remote_fs", SPECIAL_REMOTE_FS_TARGET"remote-fs.target", | ||||
244 | "syslog", NULL((void*)0), | ||||
245 | "time", SPECIAL_TIME_SYNC_TARGET"time-sync.target", | ||||
246 | }; | ||||
247 | |||||
248 | const char *filename; | ||||
249 | char *filename_no_sh, *e, *m; | ||||
250 | const char *n; | ||||
251 | unsigned i; | ||||
252 | int r; | ||||
253 | |||||
254 | assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("name"), "../src/sysv-generator/sysv-generator.c" , 254, __PRETTY_FUNCTION__); } while (0); | ||||
255 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/sysv-generator/sysv-generator.c" , 255, __PRETTY_FUNCTION__); } while (0); | ||||
256 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/sysv-generator/sysv-generator.c" , 256, __PRETTY_FUNCTION__); } while (0); | ||||
257 | |||||
258 | filename = basename(s->path); | ||||
259 | |||||
260 | n = *name == '$' ? name + 1 : name; | ||||
261 | |||||
262 | for (i = 0; i < ELEMENTSOF(table)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(table), typeof(&*(table))), sizeof(table)/sizeof( (table)[0]), ((void)0))); i += 2) { | ||||
263 | if (!streq(table[i], n)(strcmp((table[i]),(n)) == 0)) | ||||
264 | continue; | ||||
265 | |||||
266 | if (!table[i+1]) { | ||||
267 | *ret = NULL((void*)0); | ||||
268 | return 0; | ||||
269 | } | ||||
270 | |||||
271 | m = strdup(table[i+1]); | ||||
272 | if (!m) | ||||
273 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 273, __func__); | ||||
274 | |||||
275 | *ret = m; | ||||
276 | return 1; | ||||
277 | } | ||||
278 | |||||
279 | /* If we don't know this name, fallback heuristics to figure | ||||
280 | * out whether something is a target or a service alias. */ | ||||
281 | |||||
282 | /* Facilities starting with $ are most likely targets */ | ||||
283 | if (*name == '$') { | ||||
284 | r = unit_name_build(n, NULL((void*)0), ".target", ret); | ||||
285 | if (r < 0) | ||||
286 | return log_error_errno(r, "[%s:%u] Could not build name for facility %s: %m", s->path, line, name)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 286, __func__, "[%s:%u] Could not build name for facility %s: %m" , s->path, line, name) : -abs(_e); }); | ||||
287 | |||||
288 | return 1; | ||||
289 | } | ||||
290 | |||||
291 | /* Strip ".sh" suffix from file name for comparison */ | ||||
292 | filename_no_sh = strdupa(filename)(__extension__ ({ const char *__old = (filename); size_t __len = strlen (__old) + 1; char *__new = (char *) __builtin_alloca (__len); (char *) memcpy (__new, __old, __len); })); | ||||
293 | e = endswith(filename_no_sh, ".sh"); | ||||
294 | if (e) { | ||||
295 | *e = '\0'; | ||||
296 | filename = filename_no_sh; | ||||
297 | } | ||||
298 | |||||
299 | /* Names equaling the file name of the services are redundant */ | ||||
300 | if (streq_ptr(n, filename)) { | ||||
301 | *ret = NULL((void*)0); | ||||
302 | return 0; | ||||
303 | } | ||||
304 | |||||
305 | /* Everything else we assume to be normal service names */ | ||||
306 | m = sysv_translate_name(n); | ||||
307 | if (!m) | ||||
308 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 308, __func__); | ||||
309 | |||||
310 | *ret = m; | ||||
311 | return 1; | ||||
312 | } | ||||
313 | |||||
314 | static int handle_provides(SysvStub *s, unsigned line, const char *full_text, const char *text) { | ||||
315 | int r; | ||||
316 | |||||
317 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/sysv-generator/sysv-generator.c" , 317, __PRETTY_FUNCTION__); } while (0); | ||||
318 | assert(full_text)do { if ((__builtin_expect(!!(!(full_text)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("full_text"), "../src/sysv-generator/sysv-generator.c" , 318, __PRETTY_FUNCTION__); } while (0); | ||||
319 | assert(text)do { if ((__builtin_expect(!!(!(text)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("text"), "../src/sysv-generator/sysv-generator.c" , 319, __PRETTY_FUNCTION__); } while (0); | ||||
320 | |||||
321 | for (;;) { | ||||
322 | _cleanup_free___attribute__((cleanup(freep))) char *word = NULL((void*)0), *m = NULL((void*)0); | ||||
323 | |||||
324 | r = extract_first_word(&text, &word, NULL((void*)0), EXTRACT_QUOTES|EXTRACT_RELAX); | ||||
325 | if (r < 0) | ||||
326 | return log_error_errno(r, "[%s:%u] Failed to parse word from provides string: %m", s->path, line)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 326, __func__, "[%s:%u] Failed to parse word from provides string: %m" , s->path, line) : -abs(_e); }); | ||||
327 | if (r == 0) | ||||
328 | break; | ||||
329 | |||||
330 | r = sysv_translate_facility(s, line, word, &m); | ||||
331 | if (r <= 0) /* continue on error */ | ||||
332 | continue; | ||||
333 | |||||
334 | switch (unit_name_to_type(m)) { | ||||
335 | |||||
336 | case UNIT_SERVICE: | ||||
337 | log_debug("Adding Provides: alias '%s' for '%s'", m, s->name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 337, __func__, "Adding Provides: alias '%s' for '%s'" , m, s->name) : -abs(_e); }); | ||||
338 | r = add_alias(s->name, m); | ||||
339 | if (r < 0) | ||||
340 | log_warning_errno(r, "[%s:%u] Failed to add LSB Provides name %s, ignoring: %m", s->path, line, m)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 340, __func__, "[%s:%u] Failed to add LSB Provides name %s, ignoring: %m" , s->path, line, m) : -abs(_e); }); | ||||
341 | break; | ||||
342 | |||||
343 | case UNIT_TARGET: | ||||
344 | |||||
345 | /* NB: SysV targets which are provided by a | ||||
346 | * service are pulled in by the services, as | ||||
347 | * an indication that the generic service is | ||||
348 | * now available. This is strictly one-way. | ||||
349 | * The targets do NOT pull in SysV services! */ | ||||
350 | |||||
351 | r = strv_extend(&s->before, m); | ||||
352 | if (r < 0) | ||||
353 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 353, __func__); | ||||
354 | |||||
355 | r = strv_extend(&s->wants, m); | ||||
356 | if (r < 0) | ||||
357 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 357, __func__); | ||||
358 | |||||
359 | if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)(strcmp((m),("network-online.target")) == 0)) { | ||||
360 | r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET"network.target"); | ||||
361 | if (r < 0) | ||||
362 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 362, __func__); | ||||
363 | r = strv_extend(&s->wants, SPECIAL_NETWORK_TARGET"network.target"); | ||||
364 | if (r < 0) | ||||
365 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 365, __func__); | ||||
366 | } | ||||
367 | |||||
368 | break; | ||||
369 | |||||
370 | case _UNIT_TYPE_INVALID: | ||||
371 | log_warning("Unit name '%s' is invalid", m)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 371, __func__, "Unit name '%s' is invalid" , m) : -abs(_e); }); | ||||
372 | break; | ||||
373 | |||||
374 | default: | ||||
375 | log_warning("Unknown unit type for unit '%s'", m)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 375, __func__, "Unknown unit type for unit '%s'" , m) : -abs(_e); }); | ||||
376 | } | ||||
377 | } | ||||
378 | |||||
379 | return 0; | ||||
380 | } | ||||
381 | |||||
382 | static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text, const char *text) { | ||||
383 | int r; | ||||
384 | |||||
385 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/sysv-generator/sysv-generator.c" , 385, __PRETTY_FUNCTION__); } while (0); | ||||
386 | assert(full_text)do { if ((__builtin_expect(!!(!(full_text)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("full_text"), "../src/sysv-generator/sysv-generator.c" , 386, __PRETTY_FUNCTION__); } while (0); | ||||
387 | assert(text)do { if ((__builtin_expect(!!(!(text)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("text"), "../src/sysv-generator/sysv-generator.c" , 387, __PRETTY_FUNCTION__); } while (0); | ||||
388 | |||||
389 | for (;;) { | ||||
390 | _cleanup_free___attribute__((cleanup(freep))) char *word = NULL((void*)0), *m = NULL((void*)0); | ||||
391 | bool_Bool is_before; | ||||
392 | |||||
393 | r = extract_first_word(&text, &word, NULL((void*)0), EXTRACT_QUOTES|EXTRACT_RELAX); | ||||
394 | if (r < 0) | ||||
395 | return log_error_errno(r, "[%s:%u] Failed to parse word from provides string: %m", s->path, line)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 395, __func__, "[%s:%u] Failed to parse word from provides string: %m" , s->path, line) : -abs(_e); }); | ||||
396 | if (r == 0) | ||||
397 | break; | ||||
398 | |||||
399 | r = sysv_translate_facility(s, line, word, &m); | ||||
400 | if (r <= 0) /* continue on error */ | ||||
401 | continue; | ||||
402 | |||||
403 | is_before = startswith_no_case(full_text, "X-Start-Before:"); | ||||
404 | |||||
405 | if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)(strcmp((m),("network-online.target")) == 0) && !is_before) { | ||||
| |||||
406 | /* the network-online target is special, as it needs to be actively pulled in */ | ||||
407 | r = strv_extend(&s->after, m); | ||||
408 | if (r < 0) | ||||
409 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 409, __func__); | ||||
410 | |||||
411 | r = strv_extend(&s->wants, m); | ||||
412 | } else | ||||
413 | r = strv_extend(is_before ? &s->before : &s->after, m); | ||||
414 | if (r < 0) | ||||
415 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 415, __func__); | ||||
416 | } | ||||
417 | |||||
418 | return 0; | ||||
419 | } | ||||
420 | |||||
421 | static int load_sysv(SysvStub *s) { | ||||
422 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f; | ||||
423 | unsigned line = 0; | ||||
424 | int r; | ||||
425 | enum { | ||||
426 | NORMAL, | ||||
427 | DESCRIPTION, | ||||
428 | LSB, | ||||
429 | LSB_DESCRIPTION, | ||||
430 | USAGE_CONTINUATION | ||||
431 | } state = NORMAL; | ||||
432 | _cleanup_free___attribute__((cleanup(freep))) char *short_description = NULL((void*)0), *long_description = NULL((void*)0), *chkconfig_description = NULL((void*)0); | ||||
433 | char *description; | ||||
434 | bool_Bool supports_reload = false0; | ||||
435 | char l[LINE_MAX2048]; | ||||
436 | |||||
437 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/sysv-generator/sysv-generator.c" , 437, __PRETTY_FUNCTION__); } while (0); | ||||
| |||||
438 | |||||
439 | f = fopen(s->path, "re"); | ||||
440 | if (!f) { | ||||
441 | if (errno(*__errno_location ()) == ENOENT2) | ||||
442 | return 0; | ||||
443 | |||||
444 | return log_error_errno(errno, "Failed to open %s: %m", s->path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/sysv-generator/sysv-generator.c" , 444, __func__, "Failed to open %s: %m", s->path) : -abs( _e); }); | ||||
445 | } | ||||
446 | |||||
447 | log_debug("Loading SysV script %s", s->path)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 447, __func__, "Loading SysV script %s" , s->path) : -abs(_e); }); | ||||
448 | |||||
449 | FOREACH_LINE(l, f, goto fail)for (;;) if (!fgets(l, sizeof(l), f)) { if (ferror(f)) { goto fail; } break; } else { | ||||
450 | char *t; | ||||
451 | |||||
452 | line++; | ||||
453 | |||||
454 | t = strstrip(l); | ||||
455 | if (*t != '#') { | ||||
456 | /* Try to figure out whether this init script supports | ||||
457 | * the reload operation. This heuristic looks for | ||||
458 | * "Usage" lines which include the reload option. */ | ||||
459 | if ( state == USAGE_CONTINUATION || | ||||
460 | (state == NORMAL && strcasestr(t, "usage"))) { | ||||
461 | if (usage_contains_reload(t)) { | ||||
462 | supports_reload = true1; | ||||
463 | state = NORMAL; | ||||
464 | } else if (t[strlen(t)-1] == '\\') | ||||
465 | state = USAGE_CONTINUATION; | ||||
466 | else | ||||
467 | state = NORMAL; | ||||
468 | } | ||||
469 | |||||
470 | continue; | ||||
471 | } | ||||
472 | |||||
473 | if (state
| ||||
474 | state = LSB; | ||||
475 | s->has_lsb = true1; | ||||
476 | continue; | ||||
477 | } | ||||
478 | |||||
479 | if (IN_SET(state, LSB_DESCRIPTION, LSB)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){LSB_DESCRIPTION, LSB})/sizeof(int)]; switch (state) { case LSB_DESCRIPTION: case LSB: _found = 1; break; default : break; } _found; }) && streq(t, "### END INIT INFO")(strcmp((t),("### END INIT INFO")) == 0)) { | ||||
480 | state = NORMAL; | ||||
481 | continue; | ||||
482 | } | ||||
483 | |||||
484 | t++; | ||||
485 | t += strspn(t, WHITESPACE" \t\n\r"); | ||||
486 | |||||
487 | if (state
| ||||
488 | |||||
489 | /* Try to parse Red Hat style description */ | ||||
490 | |||||
491 | if (startswith_no_case(t, "description:")) { | ||||
492 | |||||
493 | size_t k; | ||||
494 | const char *j; | ||||
495 | |||||
496 | k = strlen(t); | ||||
497 | if (k > 0 && t[k-1] == '\\') { | ||||
498 | state = DESCRIPTION; | ||||
499 | t[k-1] = 0; | ||||
500 | } | ||||
501 | |||||
502 | j = empty_to_null(strstrip(t+12)); | ||||
503 | |||||
504 | r = free_and_strdup(&chkconfig_description, j); | ||||
505 | if (r < 0) | ||||
506 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 506, __func__); | ||||
507 | |||||
508 | } else if (startswith_no_case(t, "pidfile:")) { | ||||
509 | const char *fn; | ||||
510 | |||||
511 | state = NORMAL; | ||||
512 | |||||
513 | fn = strstrip(t+8); | ||||
514 | if (!path_is_absolute(fn)) { | ||||
515 | log_error("[%s:%u] PID file not absolute. Ignoring.", s->path, line)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 515, __func__, "[%s:%u] PID file not absolute. Ignoring." , s->path, line) : -abs(_e); }); | ||||
516 | continue; | ||||
517 | } | ||||
518 | |||||
519 | r = free_and_strdup(&s->pid_file, fn); | ||||
520 | if (r < 0) | ||||
521 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 521, __func__); | ||||
522 | } | ||||
523 | |||||
524 | } else if (state
| ||||
525 | |||||
526 | /* Try to parse Red Hat style description | ||||
527 | * continuation */ | ||||
528 | |||||
529 | size_t k; | ||||
530 | char *j; | ||||
531 | |||||
532 | k = strlen(t); | ||||
533 | if (k > 0 && t[k-1] == '\\') | ||||
534 | t[k-1] = 0; | ||||
535 | else | ||||
536 | state = NORMAL; | ||||
537 | |||||
538 | j = strstrip(t); | ||||
539 | if (!isempty(j)) { | ||||
540 | char *d = NULL((void*)0); | ||||
541 | |||||
542 | if (chkconfig_description) | ||||
543 | d = strjoin(chkconfig_description, " ", j)strjoin_real((chkconfig_description), " ", j, ((void*)0)); | ||||
544 | else | ||||
545 | d = strdup(j); | ||||
546 | if (!d) | ||||
547 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 547, __func__); | ||||
548 | |||||
549 | free(chkconfig_description); | ||||
550 | chkconfig_description = d; | ||||
551 | } | ||||
552 | |||||
553 | } else if (IN_SET(state, LSB, LSB_DESCRIPTION)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){LSB, LSB_DESCRIPTION})/sizeof(int)]; switch (state) { case LSB: case LSB_DESCRIPTION: _found = 1; break; default : break; } _found; })) { | ||||
554 | |||||
555 | if (startswith_no_case(t, "Provides:")) { | ||||
556 | state = LSB; | ||||
557 | |||||
558 | r = handle_provides(s, line, t, t + 9); | ||||
559 | if (r < 0) | ||||
560 | return r; | ||||
561 | |||||
562 | } else if (startswith_no_case(t, "Required-Start:") || | ||||
563 | startswith_no_case(t, "Should-Start:") || | ||||
564 | startswith_no_case(t, "X-Start-Before:") || | ||||
565 | startswith_no_case(t, "X-Start-After:")) { | ||||
566 | |||||
567 | state = LSB; | ||||
568 | |||||
569 | r = handle_dependencies(s, line, t, strchr(t, ':') + 1); | ||||
570 | if (r < 0) | ||||
571 | return r; | ||||
572 | |||||
573 | } else if (startswith_no_case(t, "Description:")) { | ||||
574 | const char *j; | ||||
575 | |||||
576 | state = LSB_DESCRIPTION; | ||||
577 | |||||
578 | j = empty_to_null(strstrip(t+12)); | ||||
579 | |||||
580 | r = free_and_strdup(&long_description, j); | ||||
581 | if (r < 0) | ||||
582 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 582, __func__); | ||||
583 | |||||
584 | } else if (startswith_no_case(t, "Short-Description:")) { | ||||
585 | const char *j; | ||||
586 | |||||
587 | state = LSB; | ||||
588 | |||||
589 | j = empty_to_null(strstrip(t+18)); | ||||
590 | |||||
591 | r = free_and_strdup(&short_description, j); | ||||
592 | if (r < 0) | ||||
593 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 593, __func__); | ||||
594 | |||||
595 | } else if (state == LSB_DESCRIPTION) { | ||||
596 | |||||
597 | if (startswith(l, "#\t") || startswith(l, "# ")) { | ||||
598 | const char *j; | ||||
599 | |||||
600 | j = strstrip(t); | ||||
601 | if (!isempty(j)) { | ||||
602 | char *d = NULL((void*)0); | ||||
603 | |||||
604 | if (long_description) | ||||
605 | d = strjoin(long_description, " ", t)strjoin_real((long_description), " ", t, ((void*)0)); | ||||
606 | else | ||||
607 | d = strdup(j); | ||||
608 | if (!d) | ||||
609 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 609, __func__); | ||||
610 | |||||
611 | free(long_description); | ||||
612 | long_description = d; | ||||
613 | } | ||||
614 | |||||
615 | } else | ||||
616 | state = LSB; | ||||
617 | } | ||||
618 | } | ||||
619 | } | ||||
620 | |||||
621 | s->reload = supports_reload; | ||||
622 | |||||
623 | /* We use the long description only if | ||||
624 | * no short description is set. */ | ||||
625 | |||||
626 | if (short_description) | ||||
627 | description = short_description; | ||||
628 | else if (chkconfig_description) | ||||
629 | description = chkconfig_description; | ||||
630 | else if (long_description) | ||||
631 | description = long_description; | ||||
632 | else | ||||
633 | description = NULL((void*)0); | ||||
634 | |||||
635 | if (description) { | ||||
636 | char *d; | ||||
637 | |||||
638 | d = strappend(s->has_lsb ? "LSB: " : "SYSV: ", description); | ||||
639 | if (!d) | ||||
640 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 640, __func__); | ||||
641 | |||||
642 | s->description = d; | ||||
643 | } | ||||
644 | |||||
645 | s->loaded = true1; | ||||
646 | return 0; | ||||
647 | |||||
648 | fail: | ||||
649 | return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/sysv-generator/sysv-generator.c" , 649, __func__, "Failed to read configuration file '%s': %m" , s->path) : -abs(_e); }); | ||||
650 | } | ||||
651 | |||||
652 | static int fix_order(SysvStub *s, Hashmap *all_services) { | ||||
653 | SysvStub *other; | ||||
654 | Iterator j; | ||||
655 | int r; | ||||
656 | |||||
657 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/sysv-generator/sysv-generator.c" , 657, __PRETTY_FUNCTION__); } while (0); | ||||
658 | |||||
659 | if (!s->loaded) | ||||
660 | return 0; | ||||
661 | |||||
662 | if (s->sysv_start_priority < 0) | ||||
663 | return 0; | ||||
664 | |||||
665 | HASHMAP_FOREACH(other, all_services, j)for ((j) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((all_services), & (j), (void**)&(other), ((void*)0)); ) { | ||||
666 | if (s == other) | ||||
667 | continue; | ||||
668 | |||||
669 | if (!other->loaded) | ||||
670 | continue; | ||||
671 | |||||
672 | if (other->sysv_start_priority < 0) | ||||
673 | continue; | ||||
674 | |||||
675 | /* If both units have modern headers we don't care | ||||
676 | * about the priorities */ | ||||
677 | if (s->has_lsb && other->has_lsb) | ||||
678 | continue; | ||||
679 | |||||
680 | if (other->sysv_start_priority < s->sysv_start_priority) { | ||||
681 | r = strv_extend(&s->after, other->name); | ||||
682 | if (r < 0) | ||||
683 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 683, __func__); | ||||
684 | |||||
685 | } else if (other->sysv_start_priority > s->sysv_start_priority) { | ||||
686 | r = strv_extend(&s->before, other->name); | ||||
687 | if (r < 0) | ||||
688 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 688, __func__); | ||||
689 | } else | ||||
690 | continue; | ||||
691 | |||||
692 | /* FIXME: Maybe we should compare the name here lexicographically? */ | ||||
693 | } | ||||
694 | |||||
695 | return 0; | ||||
696 | } | ||||
697 | |||||
698 | static int acquire_search_path(const char *def, const char *envvar, char ***ret) { | ||||
699 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0); | ||||
700 | const char *e; | ||||
701 | int r; | ||||
702 | |||||
703 | assert(def)do { if ((__builtin_expect(!!(!(def)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("def"), "../src/sysv-generator/sysv-generator.c" , 703, __PRETTY_FUNCTION__); } while (0); | ||||
704 | assert(envvar)do { if ((__builtin_expect(!!(!(envvar)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("envvar"), "../src/sysv-generator/sysv-generator.c" , 704, __PRETTY_FUNCTION__); } while (0); | ||||
705 | |||||
706 | e = getenv(envvar); | ||||
707 | if (e) { | ||||
708 | r = path_split_and_make_absolute(e, &l); | ||||
709 | if (r < 0) | ||||
710 | return log_error_errno(r, "Failed to make $%s search path absolute: %m", envvar)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 710, __func__, "Failed to make $%s search path absolute: %m" , envvar) : -abs(_e); }); | ||||
711 | } | ||||
712 | |||||
713 | if (strv_isempty(l)) { | ||||
714 | strv_free(l); | ||||
715 | |||||
716 | l = strv_new(def, NULL((void*)0)); | ||||
717 | if (!l) | ||||
718 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 718, __func__); | ||||
719 | } | ||||
720 | |||||
721 | if (!path_strv_resolve_uniq(l, NULL((void*)0))) | ||||
722 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 722, __func__); | ||||
723 | |||||
724 | *ret = TAKE_PTR(l)({ typeof(l) _ptr_ = (l); (l) = ((void*)0); _ptr_; }); | ||||
725 | |||||
726 | return 0; | ||||
727 | } | ||||
728 | |||||
729 | static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { | ||||
730 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **sysvinit_path = NULL((void*)0); | ||||
731 | char **path; | ||||
732 | int r; | ||||
733 | |||||
734 | assert(lp)do { if ((__builtin_expect(!!(!(lp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lp"), "../src/sysv-generator/sysv-generator.c" , 734, __PRETTY_FUNCTION__); } while (0); | ||||
735 | |||||
736 | r = acquire_search_path(SYSTEM_SYSVINIT_PATH"/etc/init.d", "SYSTEMD_SYSVINIT_PATH", &sysvinit_path); | ||||
737 | if (r < 0) | ||||
738 | return r; | ||||
739 | |||||
740 | STRV_FOREACH(path, sysvinit_path)for ((path) = (sysvinit_path); (path) && *(path); (path )++) { | ||||
741 | _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0); | ||||
742 | struct dirent *de; | ||||
743 | |||||
744 | d = opendir(*path); | ||||
745 | if (!d) { | ||||
746 | if (errno(*__errno_location ()) != ENOENT2) | ||||
747 | log_warning_errno(errno, "Opening %s failed, ignoring: %m", *path)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/sysv-generator/sysv-generator.c" , 747, __func__, "Opening %s failed, ignoring: %m", *path) : - abs(_e); }); | ||||
748 | continue; | ||||
749 | } | ||||
750 | |||||
751 | FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", *path))for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location ()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location ( )) > 0) { ({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm (_realm) >= ((_level) & 0x07)) ? log_internal_realm((( _realm) << 10 | (_level)), _e, "../src/sysv-generator/sysv-generator.c" , 751, __func__, "Failed to enumerate directory %s, ignoring: %m" , *path) : -abs(_e); }); } break; } else if (hidden_or_backup_file ((de)->d_name)) continue; else { | ||||
752 | _cleanup_free___attribute__((cleanup(freep))) char *fpath = NULL((void*)0), *name = NULL((void*)0); | ||||
753 | _cleanup_(free_sysvstubp)__attribute__((cleanup(free_sysvstubp))) SysvStub *service = NULL((void*)0); | ||||
754 | struct stat st; | ||||
755 | |||||
756 | if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) { | ||||
757 | log_warning_errno(errno, "stat() failed on %s/%s, ignoring: %m", *path, de->d_name)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/sysv-generator/sysv-generator.c" , 757, __func__, "stat() failed on %s/%s, ignoring: %m", *path , de->d_name) : -abs(_e); }); | ||||
758 | continue; | ||||
759 | } | ||||
760 | |||||
761 | if (!(st.st_mode & S_IXUSR0100)) | ||||
762 | continue; | ||||
763 | |||||
764 | if (!S_ISREG(st.st_mode)((((st.st_mode)) & 0170000) == (0100000))) | ||||
765 | continue; | ||||
766 | |||||
767 | name = sysv_translate_name(de->d_name); | ||||
768 | if (!name) | ||||
769 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 769, __func__); | ||||
770 | |||||
771 | if (hashmap_contains(all_services, name)) | ||||
772 | continue; | ||||
773 | |||||
774 | r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name); | ||||
775 | if (r < 0 && !IN_SET(r, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-40, -132, -99})/sizeof(int)]; switch(r) { case -40: case -132: case -99: _found = 1; break; default: break; } _found; })) { | ||||
776 | log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 776, __func__, "Failed to detect whether %s exists, skipping: %m" , name) : -abs(_e); }); | ||||
777 | continue; | ||||
778 | } else if (r != 0) { | ||||
779 | log_debug("Native unit for %s already exists, skipping.", name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 779, __func__, "Native unit for %s already exists, skipping." , name) : -abs(_e); }); | ||||
780 | continue; | ||||
781 | } | ||||
782 | |||||
783 | fpath = strjoin(*path, "/", de->d_name)strjoin_real((*path), "/", de->d_name, ((void*)0)); | ||||
784 | if (!fpath) | ||||
785 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 785, __func__); | ||||
786 | |||||
787 | service = new0(SysvStub, 1)((SysvStub*) calloc((1), sizeof(SysvStub))); | ||||
788 | if (!service) | ||||
789 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 789, __func__); | ||||
790 | |||||
791 | service->sysv_start_priority = -1; | ||||
792 | service->name = TAKE_PTR(name)({ typeof(name) _ptr_ = (name); (name) = ((void*)0); _ptr_; } ); | ||||
793 | service->path = TAKE_PTR(fpath)({ typeof(fpath) _ptr_ = (fpath); (fpath) = ((void*)0); _ptr_ ; }); | ||||
794 | |||||
795 | r = hashmap_put(all_services, service->name, service); | ||||
796 | if (r < 0) | ||||
797 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 797, __func__); | ||||
798 | |||||
799 | service = NULL((void*)0); | ||||
800 | } | ||||
801 | } | ||||
802 | |||||
803 | return 0; | ||||
804 | } | ||||
805 | |||||
806 | static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) { | ||||
807 | Set *runlevel_services[ELEMENTSOF(rcnd_table)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(rcnd_table), typeof(&*(rcnd_table))), sizeof(rcnd_table )/sizeof((rcnd_table)[0]), ((void)0)))] = {}; | ||||
808 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **sysvrcnd_path = NULL((void*)0); | ||||
809 | SysvStub *service; | ||||
810 | unsigned i; | ||||
811 | Iterator j; | ||||
812 | char **p; | ||||
813 | int r; | ||||
814 | |||||
815 | assert(lp)do { if ((__builtin_expect(!!(!(lp)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("lp"), "../src/sysv-generator/sysv-generator.c" , 815, __PRETTY_FUNCTION__); } while (0); | ||||
816 | |||||
817 | r = acquire_search_path(SYSTEM_SYSVRCND_PATH"/etc/rc.d", "SYSTEMD_SYSVRCND_PATH", &sysvrcnd_path); | ||||
818 | if (r < 0) | ||||
819 | return r; | ||||
820 | |||||
821 | STRV_FOREACH(p, sysvrcnd_path)for ((p) = (sysvrcnd_path); (p) && *(p); (p)++) { | ||||
822 | for (i = 0; i < ELEMENTSOF(rcnd_table)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(rcnd_table), typeof(&*(rcnd_table))), sizeof(rcnd_table )/sizeof((rcnd_table)[0]), ((void)0))); i ++) { | ||||
823 | |||||
824 | _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0); | ||||
825 | _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0); | ||||
826 | struct dirent *de; | ||||
827 | |||||
828 | path = strjoin(*p, "/", rcnd_table[i].path)strjoin_real((*p), "/", rcnd_table[i].path, ((void*)0)); | ||||
829 | if (!path) { | ||||
830 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 830, __func__); | ||||
831 | goto finish; | ||||
832 | } | ||||
833 | |||||
834 | d = opendir(path); | ||||
835 | if (!d) { | ||||
836 | if (errno(*__errno_location ()) != ENOENT2) | ||||
837 | log_warning_errno(errno, "Opening %s failed, ignoring: %m", path)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/sysv-generator/sysv-generator.c" , 837, __func__, "Opening %s failed, ignoring: %m", path) : - abs(_e); }); | ||||
838 | |||||
839 | continue; | ||||
840 | } | ||||
841 | |||||
842 | FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", path))for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location ()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location ( )) > 0) { ({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm (_realm) >= ((_level) & 0x07)) ? log_internal_realm((( _realm) << 10 | (_level)), _e, "../src/sysv-generator/sysv-generator.c" , 842, __func__, "Failed to enumerate directory %s, ignoring: %m" , path) : -abs(_e); }); } break; } else if (hidden_or_backup_file ((de)->d_name)) continue; else { | ||||
843 | _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0), *fpath = NULL((void*)0); | ||||
844 | int a, b; | ||||
845 | |||||
846 | if (de->d_name[0] != 'S') | ||||
847 | continue; | ||||
848 | |||||
849 | if (strlen(de->d_name) < 4) | ||||
850 | continue; | ||||
851 | |||||
852 | a = undecchar(de->d_name[1]); | ||||
853 | b = undecchar(de->d_name[2]); | ||||
854 | |||||
855 | if (a < 0 || b < 0) | ||||
856 | continue; | ||||
857 | |||||
858 | fpath = strjoin(*p, "/", de->d_name)strjoin_real((*p), "/", de->d_name, ((void*)0)); | ||||
859 | if (!fpath) { | ||||
860 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 860, __func__); | ||||
861 | goto finish; | ||||
862 | } | ||||
863 | |||||
864 | name = sysv_translate_name(de->d_name + 3); | ||||
865 | if (!name) { | ||||
866 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 866, __func__); | ||||
867 | goto finish; | ||||
868 | } | ||||
869 | |||||
870 | service = hashmap_get(all_services, name); | ||||
871 | if (!service) { | ||||
872 | log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 872, __func__, "Ignoring %s symlink in %s, not generating %s." , de->d_name, rcnd_table[i].path, name) : -abs(_e); }); | ||||
873 | continue; | ||||
874 | } | ||||
875 | |||||
876 | service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority)__extension__ ({ const typeof((a*10 + b)) __unique_prefix_A8 = ((a*10 + b)); const typeof((service->sysv_start_priority) ) __unique_prefix_B9 = ((service->sysv_start_priority)); __unique_prefix_A8 > __unique_prefix_B9 ? __unique_prefix_A8 : __unique_prefix_B9 ; }); | ||||
877 | |||||
878 | r = set_ensure_allocated(&runlevel_services[i], NULL)internal_set_ensure_allocated(&runlevel_services[i], ((void *)0) ); | ||||
879 | if (r < 0) { | ||||
880 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 880, __func__); | ||||
881 | goto finish; | ||||
882 | } | ||||
883 | |||||
884 | r = set_put(runlevel_services[i], service); | ||||
885 | if (r < 0) { | ||||
886 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 886, __func__); | ||||
887 | goto finish; | ||||
888 | } | ||||
889 | } | ||||
890 | } | ||||
891 | } | ||||
892 | |||||
893 | for (i = 0; i < ELEMENTSOF(rcnd_table)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(rcnd_table), typeof(&*(rcnd_table))), sizeof(rcnd_table )/sizeof((rcnd_table)[0]), ((void)0))); i ++) | ||||
894 | SET_FOREACH(service, runlevel_services[i], j)for ((j) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); set_iterate((runlevel_services[i]), &(j), (void**)&(service)); ) { | ||||
895 | r = strv_extend(&service->before, rcnd_table[i].target); | ||||
896 | if (r < 0) { | ||||
897 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 897, __func__); | ||||
898 | goto finish; | ||||
899 | } | ||||
900 | r = strv_extend(&service->wanted_by, rcnd_table[i].target); | ||||
901 | if (r < 0) { | ||||
902 | log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 902, __func__); | ||||
903 | goto finish; | ||||
904 | } | ||||
905 | } | ||||
906 | |||||
907 | r = 0; | ||||
908 | |||||
909 | finish: | ||||
910 | for (i = 0; i < ELEMENTSOF(rcnd_table)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(rcnd_table), typeof(&*(rcnd_table))), sizeof(rcnd_table )/sizeof((rcnd_table)[0]), ((void)0))); i++) | ||||
911 | set_free(runlevel_services[i]); | ||||
912 | |||||
913 | return r; | ||||
914 | } | ||||
915 | |||||
916 | int main(int argc, char *argv[]) { | ||||
917 | _cleanup_(free_sysvstub_hashmapp)__attribute__((cleanup(free_sysvstub_hashmapp))) Hashmap *all_services = NULL((void*)0); | ||||
918 | _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths lp = {}; | ||||
919 | SysvStub *service; | ||||
920 | Iterator j; | ||||
921 | int r; | ||||
922 | |||||
923 | if (argc > 1 && argc != 4) { | ||||
924 | log_error("This program takes three or no arguments.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 924, __func__, "This program takes three or no arguments." ) : -abs(_e); }); | ||||
925 | return EXIT_FAILURE1; | ||||
926 | } | ||||
927 | |||||
928 | if (argc > 1) | ||||
929 | arg_dest = argv[3]; | ||||
930 | |||||
931 | log_set_prohibit_ipc(true1); | ||||
932 | log_set_target(LOG_TARGET_AUTO); | ||||
933 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); | ||||
934 | log_open(); | ||||
935 | |||||
936 | umask(0022); | ||||
937 | |||||
938 | r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL((void*)0)); | ||||
939 | if (r < 0) { | ||||
940 | log_error_errno(r, "Failed to find lookup paths: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/sysv-generator/sysv-generator.c", 940, __func__, "Failed to find lookup paths: %m" ) : -abs(_e); }); | ||||
941 | goto finish; | ||||
942 | } | ||||
943 | |||||
944 | all_services = hashmap_new(&string_hash_ops)internal_hashmap_new(&string_hash_ops ); | ||||
945 | if (!all_services) { | ||||
946 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/sysv-generator/sysv-generator.c" , 946, __func__); | ||||
947 | goto finish; | ||||
948 | } | ||||
949 | |||||
950 | r = enumerate_sysv(&lp, all_services); | ||||
951 | if (r < 0) | ||||
952 | goto finish; | ||||
953 | |||||
954 | r = set_dependencies_from_rcnd(&lp, all_services); | ||||
955 | if (r < 0) | ||||
956 | goto finish; | ||||
957 | |||||
958 | HASHMAP_FOREACH(service, all_services, j)for ((j) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((all_services), & (j), (void**)&(service), ((void*)0)); ) | ||||
959 | (void) load_sysv(service); | ||||
960 | |||||
961 | HASHMAP_FOREACH(service, all_services, j)for ((j) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((all_services), & (j), (void**)&(service), ((void*)0)); ) { | ||||
962 | (void) fix_order(service, all_services); | ||||
963 | (void) generate_unit_file(service); | ||||
964 | } | ||||
965 | |||||
966 | r = 0; | ||||
967 | |||||
968 | finish: | ||||
969 | return r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0; | ||||
970 | } |