| File: | build-scan/../src/sysv-generator/sysv-generator.c |
| Warning: | line 375, column 25 Potential leak of memory pointed to by 'm' |
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
| ||||
| 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_A6 = ((a*10 + b)); const typeof((service->sysv_start_priority) ) __unique_prefix_B7 = ((service->sysv_start_priority)); __unique_prefix_A6 > __unique_prefix_B7 ? __unique_prefix_A6 : __unique_prefix_B7 ; }); | ||||
| 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 | } |