File: | build-scan/../src/sysv-generator/sysv-generator.c |
Warning: | line 226, column 16 Potential leak of memory pointed to by 'c' |
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 == NORMAL && streq(t, "### BEGIN INIT INFO")(strcmp((t),("### BEGIN INIT INFO")) == 0)) { | |||
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 == NORMAL) { | |||
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 == DESCRIPTION) { | |||
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
| |||
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_A2 = ((a*10 + b)); const typeof((service->sysv_start_priority) ) __unique_prefix_B3 = ((service->sysv_start_priority)); __unique_prefix_A2 > __unique_prefix_B3 ? __unique_prefix_A2 : __unique_prefix_B3 ; }); | |||
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
| |||
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 | } |