]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/sysv-generator/sysv-generator.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / sysv-generator / sysv-generator.c
index 4e12071e93985f647ebc910228541ad4754282fc..5b30baee8422213665c8c2bfc81fd20152816d77 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
 
 #include "alloc-util.h"
 #include "dirent-util.h"
+#include "exit-status.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "generator.h"
 #include "hashmap.h"
 #include "hexdecoct.h"
 #include "install.h"
@@ -36,6 +39,7 @@
 #include "path-util.h"
 #include "set.h"
 #include "special.h"
+#include "specifier.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -92,35 +96,7 @@ static void free_sysvstub(SysvStub *s) {
 DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, free_sysvstub);
 
 static void free_sysvstub_hashmapp(Hashmap **h) {
-        SysvStub *stub;
-
-        while ((stub = hashmap_steal_first(*h)))
-                free_sysvstub(stub);
-
-        hashmap_free(*h);
-}
-
-static int add_symlink(const char *service, const char *where) {
-        const char *from, *to;
-        int r;
-
-        assert(service);
-        assert(where);
-
-        from = strjoina(arg_dest, "/", service);
-        to = strjoina(arg_dest, "/", where, ".wants/", service);
-
-        mkdir_parents_label(to, 0755);
-
-        r = symlink(from, to);
-        if (r < 0) {
-                if (errno == EEXIST)
-                        return 0;
-
-                return -errno;
-        }
-
-        return 1;
+        hashmap_free_with_destructor(*h, free_sysvstub);
 }
 
 static int add_alias(const char *service, const char *alias) {
@@ -144,6 +120,7 @@ static int add_alias(const char *service, const char *alias) {
 }
 
 static int generate_unit_file(SysvStub *s) {
+        _cleanup_free_ char *path_escaped = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         const char *unit;
         char **p;
@@ -154,6 +131,10 @@ static int generate_unit_file(SysvStub *s) {
         if (!s->loaded)
                 return 0;
 
+        path_escaped = specifier_escape(s->path);
+        if (!path_escaped)
+                return log_oom();
+
         unit = strjoina(arg_dest, "/", s->name);
 
         /* We might already have a symlink with the same name from a Provides:,
@@ -173,10 +154,17 @@ static int generate_unit_file(SysvStub *s) {
                 "[Unit]\n"
                 "Documentation=man:systemd-sysv-generator(8)\n"
                 "SourcePath=%s\n",
-                s->path);
+                path_escaped);
+
+        if (s->description) {
+                _cleanup_free_ char *t;
 
-        if (s->description)
-                fprintf(f, "Description=%s\n", s->description);
+                t = specifier_escape(s->description);
+                if (!t)
+                        return log_oom();
+
+                fprintf(f, "Description=%s\n", t);
+        }
 
         STRV_FOREACH(p, s->before)
                 fprintf(f, "Before=%s\n", *p);
@@ -196,26 +184,37 @@ static int generate_unit_file(SysvStub *s) {
                 "RemainAfterExit=%s\n",
                 yes_no(!s->pid_file));
 
-        if (s->pid_file)
-                fprintf(f, "PIDFile=%s\n", s->pid_file);
+        if (s->pid_file) {
+                _cleanup_free_ char *t;
+
+                t = specifier_escape(s->pid_file);
+                if (!t)
+                        return log_oom();
+
+                fprintf(f, "PIDFile=%s\n", t);
+        }
+
+        /* Consider two special LSB exit codes a clean exit */
+        if (s->has_lsb)
+                fprintf(f,
+                        "SuccessExitStatus=%i %i\n",
+                        EXIT_NOTINSTALLED,
+                        EXIT_NOTCONFIGURED);
 
         fprintf(f,
                 "ExecStart=%s start\n"
                 "ExecStop=%s stop\n",
-                s->path, s->path);
+                path_escaped, path_escaped);
 
         if (s->reload)
-                fprintf(f, "ExecReload=%s reload\n", s->path);
+                fprintf(f, "ExecReload=%s reload\n", path_escaped);
 
         r = fflush_and_check(f);
         if (r < 0)
                 return log_error_errno(r, "Failed to write unit %s: %m", unit);
 
-        STRV_FOREACH(p, s->wanted_by) {
-                r = add_symlink(s->name, *p);
-                if (r < 0)
-                        log_warning_errno(r, "Failed to create 'Wants' symlink to %s, ignoring: %m", *p);
-        }
+        STRV_FOREACH(p, s->wanted_by)
+                (void) generator_add_symlink(arg_dest, *p, "wants", s->name);
 
         return 1;
 }
@@ -241,13 +240,13 @@ static char *sysv_translate_name(const char *name) {
         if (res)
                 *res = 0;
 
-        if (unit_name_mangle(c, UNIT_NAME_NOGLOB, &res) < 0)
+        if (unit_name_mangle(c, 0, &res) < 0)
                 return NULL;
 
         return res;
 }
 
-static int sysv_translate_facility(const char *name, const char *filename, char **ret) {
+static int sysv_translate_facility(SysvStub *s, unsigned line, const char *name, char **ret) {
 
         /* We silently ignore the $ prefix here. According to the LSB
          * spec it simply indicates whether something is a
@@ -266,23 +265,28 @@ static int sysv_translate_facility(const char *name, const char *filename, char
                 "time",                 SPECIAL_TIME_SYNC_TARGET,
         };
 
+        const char *filename;
         char *filename_no_sh, *e, *m;
         const char *n;
         unsigned i;
         int r;
 
         assert(name);
-        assert(filename);
+        assert(s);
         assert(ret);
 
+        filename = basename(s->path);
+
         n = *name == '$' ? name + 1 : name;
 
         for (i = 0; i < ELEMENTSOF(table); i += 2) {
                 if (!streq(table[i], n))
                         continue;
 
-                if (!table[i+1])
+                if (!table[i+1]) {
+                        *ret = NULL;
                         return 0;
+                }
 
                 m = strdup(table[i+1]);
                 if (!m)
@@ -299,9 +303,9 @@ static int sysv_translate_facility(const char *name, const char *filename, char
         if (*name == '$')  {
                 r = unit_name_build(n, NULL, ".target", ret);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to build name: %m");
+                        return log_error_errno(r, "[%s:%u] Could not build name for facility %s: %m", s->path, line, name);
 
-                return r;
+                return 1;
         }
 
         /* Strip ".sh" suffix from file name for comparison */
@@ -313,8 +317,10 @@ static int sysv_translate_facility(const char *name, const char *filename, char
         }
 
         /* Names equaling the file name of the services are redundant */
-        if (streq_ptr(n, filename))
+        if (streq_ptr(n, filename)) {
+                *ret = NULL;
                 return 0;
+        }
 
         /* Everything else we assume to be normal service names */
         m = sysv_translate_name(n);
@@ -337,11 +343,11 @@ static int handle_provides(SysvStub *s, unsigned line, const char *full_text, co
 
                 r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to parse word from provides string: %m");
+                        return log_error_errno(r, "[%s:%u] Failed to parse word from provides string: %m", s->path, line);
                 if (r == 0)
                         break;
 
-                r = sysv_translate_facility(word, basename(s->path), &m);
+                r = sysv_translate_facility(s, line, word, &m);
                 if (r <= 0) /* continue on error */
                         continue;
 
@@ -374,6 +380,9 @@ static int handle_provides(SysvStub *s, unsigned line, const char *full_text, co
                                 r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET);
                                 if (r < 0)
                                         return log_oom();
+                                r = strv_extend(&s->wants, SPECIAL_NETWORK_TARGET);
+                                if (r < 0)
+                                        return log_oom();
                         }
 
                         break;
@@ -403,11 +412,11 @@ static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text
 
                 r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to parse word from provides string: %m");
+                        return log_error_errno(r, "[%s:%u] Failed to parse word from provides string: %m", s->path, line);
                 if (r == 0)
                         break;
 
-                r = sysv_translate_facility(word, basename(s->path), &m);
+                r = sysv_translate_facility(s, line, word, &m);
                 if (r <= 0) /* continue on error */
                         continue;
 
@@ -487,7 +496,7 @@ static int load_sysv(SysvStub *s) {
                         continue;
                 }
 
-                if ((state == LSB_DESCRIPTION || state == LSB) && streq(t, "### END INIT INFO")) {
+                if (IN_SET(state, LSB_DESCRIPTION, LSB) && streq(t, "### END INIT INFO")) {
                         state = NORMAL;
                         continue;
                 }
@@ -551,7 +560,7 @@ static int load_sysv(SysvStub *s) {
                                 char *d = NULL;
 
                                 if (chkconfig_description)
-                                        d = strjoin(chkconfig_description, " ", j, NULL);
+                                        d = strjoin(chkconfig_description, " ", j);
                                 else
                                         d = strdup(j);
                                 if (!d)
@@ -561,7 +570,7 @@ static int load_sysv(SysvStub *s) {
                                 chkconfig_description = d;
                         }
 
-                } else if (state == LSB || state == LSB_DESCRIPTION) {
+                } else if (IN_SET(state, LSB, LSB_DESCRIPTION)) {
 
                         if (startswith_no_case(t, "Provides:")) {
                                 state = LSB;
@@ -613,7 +622,7 @@ static int load_sysv(SysvStub *s) {
                                                 char *d = NULL;
 
                                                 if (long_description)
-                                                        d = strjoin(long_description, " ", t, NULL);
+                                                        d = strjoin(long_description, " ", t);
                                                 else
                                                         d = strdup(j);
                                                 if (!d)
@@ -732,8 +741,7 @@ static int acquire_search_path(const char *def, const char *envvar, char ***ret)
         if (!path_strv_resolve_uniq(l, NULL))
                 return log_oom();
 
-        *ret = l;
-        l = NULL;
+        *ret = TAKE_PTR(l);
 
         return 0;
 }
@@ -792,7 +800,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
                                 continue;
                         }
 
-                        fpath = strjoin(*path, "/", de->d_name, NULL);
+                        fpath = strjoin(*path, "/", de->d_name);
                         if (!fpath)
                                 return log_oom();
 
@@ -801,9 +809,8 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
                                 return log_oom();
 
                         service->sysv_start_priority = -1;
-                        service->name = name;
-                        service->path = fpath;
-                        name = fpath = NULL;
+                        service->name = TAKE_PTR(name);
+                        service->path = TAKE_PTR(fpath);
 
                         r = hashmap_put(all_services, service->name, service);
                         if (r < 0)
@@ -838,7 +845,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
                         _cleanup_free_ char *path = NULL;
                         struct dirent *de;
 
-                        path = strjoin(*p, "/", rcnd_table[i].path, NULL);
+                        path = strjoin(*p, "/", rcnd_table[i].path);
                         if (!path) {
                                 r = log_oom();
                                 goto finish;
@@ -856,7 +863,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
                                 _cleanup_free_ char *name = NULL, *fpath = NULL;
                                 int a, b;
 
-                                if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
+                                if (de->d_name[0] != 'S')
                                         continue;
 
                                 if (strlen(de->d_name) < 4)
@@ -868,7 +875,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
                                 if (a < 0 || b < 0)
                                         continue;
 
-                                fpath = strjoin(*p, "/", de->d_name, NULL);
+                                fpath = strjoin(*p, "/", de->d_name);
                                 if (!fpath) {
                                         r = log_oom();
                                         goto finish;
@@ -886,28 +893,23 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
                                         continue;
                                 }
 
-                                if (de->d_name[0] == 'S')  {
-
-                                        service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
-
-                                        r = set_ensure_allocated(&runlevel_services[i], NULL);
-                                        if (r < 0) {
-                                                log_oom();
-                                                goto finish;
-                                        }
+                                service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
 
-                                        r = set_put(runlevel_services[i], service);
-                                        if (r < 0) {
-                                                log_oom();
-                                                goto finish;
-                                        }
+                                r = set_ensure_allocated(&runlevel_services[i], NULL);
+                                if (r < 0) {
+                                        log_oom();
+                                        goto finish;
+                                }
 
+                                r = set_put(runlevel_services[i], service);
+                                if (r < 0) {
+                                        log_oom();
+                                        goto finish;
                                 }
                         }
                 }
         }
 
-
         for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
                 SET_FOREACH(service, runlevel_services[i], j) {
                         r = strv_extend(&service->before, rcnd_table[i].target);
@@ -946,7 +948,8 @@ int main(int argc, char *argv[]) {
         if (argc > 1)
                 arg_dest = argv[3];
 
-        log_set_target(LOG_TARGET_SAFE);
+        log_set_prohibit_ipc(true);
+        log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
         log_open();