chiark / gitweb /
sysv-generator: always use fstatat() if we can
[elogind.git] / src / sysv-generator / sysv-generator.c
index 6730843843ba4da0dd4c6c452812bae1360fff85..4774981016d85728ce2d3082b33befc3e54fba5e 100644 (file)
@@ -112,6 +112,27 @@ static int add_symlink(const char *service, const char *where) {
         return 1;
 }
 
+static int add_alias(const char *service, const char *alias) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        assert(service);
+        assert(alias);
+
+        link = strjoin(arg_dest, "/", alias, NULL);
+        if (!link)
+                return log_oom();
+
+        r = symlink(service, link);
+        if (r < 0) {
+                if (errno == EEXIST)
+                        return 0;
+                return -errno;
+        }
+
+        return 1;
+}
+
 static int generate_unit_file(SysvStub *s) {
         char **p;
         _cleanup_fclose_ FILE *f = NULL;
@@ -457,7 +478,9 @@ static int load_sysv(SysvStub *s) {
                                         if (r == 0)
                                                 continue;
 
-                                        if (unit_name_to_type(m) != UNIT_SERVICE) {
+                                        if (unit_name_to_type(m) == UNIT_SERVICE) {
+                                                r = add_alias(s->name, m);
+                                        } else {
                                                 /* NB: SysV targets
                                                  * which are provided
                                                  * by a service are
@@ -699,28 +722,33 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
                 }
 
                 while ((de = readdir(d))) {
-                        SysvStub *service;
-                        struct stat st;
                         _cleanup_free_ char *fpath = NULL, *name = NULL;
+                        _cleanup_free_ SysvStub *service = NULL;
+                        struct stat st;
                         int r;
 
                         if (hidden_file(de->d_name))
                                 continue;
 
-                        fpath = strjoin(*path, "/", de->d_name, NULL);
-                        if (!fpath)
-                                return log_oom();
-
-                        if (stat(fpath, &st) < 0)
+                        if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
+                                log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name);
                                 continue;
+                        }
 
                         if (!(st.st_mode & S_IXUSR))
                                 continue;
 
+                        if (!S_ISREG(st.st_mode))
+                                continue;
+
                         name = sysv_translate_name(de->d_name);
                         if (!name)
                                 return log_oom();
 
+                        fpath = strjoin(*path, "/", de->d_name, NULL);
+                        if (!fpath)
+                                return log_oom();
+
                         if (hashmap_contains(all_services, name))
                                 continue;
 
@@ -737,6 +765,7 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
                                 return log_oom();
 
                         name = fpath = NULL;
+                        service = NULL;
                 }
         }
 
@@ -919,7 +948,9 @@ int main(int argc, char *argv[]) {
                 q = load_sysv(service);
                 if (q < 0)
                         continue;
+        }
 
+        HASHMAP_FOREACH(service, all_services, j) {
                 q = fix_order(service, all_services);
                 if (q < 0)
                         continue;