chiark / gitweb /
sysv-generator: no need to check for identical symlinks source and target twice
[elogind.git] / src / sysv-generator / sysv-generator.c
index 4774981016d85728ce2d3082b33befc3e54fba5e..673f04dc27a6a317332f5ba70c8a22608738b7b0 100644 (file)
@@ -163,6 +163,14 @@ static int generate_unit_file(SysvStub *s) {
         if (!unit)
                 return log_oom();
 
+        /* We might already have a symlink with the same name from a Provides:,
+         * or from backup files like /etc/init.d/foo.bak. Real scripts always win,
+         * so remove an existing link */
+        if (is_symlink(unit)) {
+                log_warning("Overwriting existing symlink %s with real service", unit);
+                (void) unlink(unit);
+        }
+
         f = fopen(unit, "wxe");
         if (!f)
                 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
@@ -260,9 +268,9 @@ static int sysv_translate_facility(const char *name, const char *filename, char
                 "time",                 SPECIAL_TIME_SYNC_TARGET,
         };
 
-        unsigned i;
-        char *r;
+        char *filename_no_sh, *e, *r;
         const char *n;
+        unsigned i;
 
         assert(name);
         assert(_r);
@@ -284,6 +292,14 @@ static int sysv_translate_facility(const char *name, const char *filename, char
                 goto finish;
         }
 
+        /* strip ".sh" suffix from file name for comparison */
+        filename_no_sh = strdupa(filename);
+        e = endswith(filename_no_sh, ".sh");
+        if (e) {
+                *e = '\0';
+                filename = filename_no_sh;
+        }
+
         /* If we don't know this name, fallback heuristics to figure
          * out whether something is a target or a service alias. */
 
@@ -293,13 +309,12 @@ static int sysv_translate_facility(const char *name, const char *filename, char
 
                 /* Facilities starting with $ are most likely targets */
                 r = unit_name_build(n, NULL, ".target");
-        } else if (filename && streq(name, filename))
+        } else if (streq_ptr(n, filename))
                 /* Names equaling the file name of the services are redundant */
                 return 0;
         else
                 /* Everything else we assume to be normal service names */
                 r = sysv_translate_name(n);
-
         if (!r)
                 return -ENOMEM;
 
@@ -330,6 +345,8 @@ static int load_sysv(SysvStub *s) {
         if (!f)
                 return errno == ENOENT ? 0 : -errno;
 
+        log_debug("Loading SysV script %s", s->path);
+
         while (!feof(f)) {
                 char l[LINE_MAX], *t;
 
@@ -471,14 +488,13 @@ static int load_sysv(SysvStub *s) {
                                                 return -ENOMEM;
 
                                         r = sysv_translate_facility(n, basename(s->path), &m);
-
                                         if (r < 0)
                                                 return r;
-
                                         if (r == 0)
                                                 continue;
 
                                         if (unit_name_to_type(m) == UNIT_SERVICE) {
+                                                log_debug("Adding Provides: alias '%s' for '%s'", m, s->name);
                                                 r = add_alias(s->name, m);
                                         } else {
                                                 /* NB: SysV targets
@@ -730,7 +746,7 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
                         if (hidden_file(de->d_name))
                                 continue;
 
-                        if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
+                        if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
                                 log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name);
                                 continue;
                         }
@@ -745,13 +761,13 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
                         if (!name)
                                 return log_oom();
 
+                        if (hashmap_contains(all_services, name))
+                                continue;
+
                         fpath = strjoin(*path, "/", de->d_name, NULL);
                         if (!fpath)
                                 return log_oom();
 
-                        if (hashmap_contains(all_services, name))
-                                continue;
-
                         service = new0(SysvStub, 1);
                         if (!service)
                                 return log_oom();