[systemd-devel] [PATCH] add extra check for DT_UNKNOWN files in directory scan

Andrey Borzenkov arvidjaar at gmail.com
Thu Mar 3 07:27:05 PST 2011


Some file systems (at least, reiserfs) return DT_UNKNOWN for
every directory entry in readdir(). So far in several places
systemd filtered on DT_REG/DT_LNK and so skipped any file on
such filesystems. It affected systemd-update-utmp, systemd-modules-load
and systemd-tty-ask-password-agent.

This patch adds additional stat() check for file type for DT_UNKNOWN
case. Additionally, it adds check that DT_LNK really points to
regular file.

The patch fixes misterious runlevel entry in utmp discussed in
http://lists.freedesktop.org/archives/systemd-devel/2011-March/001433.html

Reported-By: tolzmann at molgen.mpg.de
Signed-off-by: Andrey Borzenkov <arvidjaar at gmail.com>

---
 src/modules-load.c           |  137 +++++++++++++++++++++++-------------------
 src/tmpfiles.c               |   22 ++++---
 src/tty-ask-password-agent.c |    8 ++-
 3 files changed, 94 insertions(+), 73 deletions(-)

diff --git a/src/modules-load.c b/src/modules-load.c
index 3e3ccb0..7d733d1 100644
--- a/src/modules-load.c
+++ b/src/modules-load.c
@@ -43,12 +43,76 @@ static int scandir_filter(const struct dirent *d) {
                 return 0;
 
         if (d->d_type != DT_REG &&
-            d->d_type != DT_LNK)
+            d->d_type != DT_LNK &&
+	    d->d_type != DT_UNKNOWN)
                 return 0;
 
         return endswith(d->d_name, ".conf");
 }
 
+static int load_modules_from_file(char *fn, char ***arguments, int *n_arguments, int *n_allocated)
+{
+	FILE *f;
+	int r = 0;
+
+	f = fopen(fn, "re");
+
+	if (!f) {
+		if (errno == ENOENT)
+			return 0;
+
+		log_error("Failed to open %s: %m", fn);
+		return -errno;
+	}
+
+	for (;;) {
+		char line[LINE_MAX], *l, *t;
+
+		if (!(fgets(line, sizeof(line), f)))
+			break;
+
+		l = strstrip(line);
+		if (*l == '#' || *l == 0)
+			continue;
+
+		if (!(t = strdup(l))) {
+			log_error("Failed to allocate module name.");
+			if (!r)
+				r = -ENOMEM;
+			continue;
+		}
+
+		if (*n_arguments >= *n_allocated) {
+			char **a;
+			unsigned m;
+
+			m = MAX(16U, *n_arguments*2);
+
+			if (!(a = realloc(*arguments, sizeof(char*) * (m+1)))) {
+				log_error("Failed to increase module array size.");
+				free(t);
+				if (!r)
+					r = -ENOMEM;
+				continue;
+			}
+
+			*arguments = a;
+			*n_allocated = m;
+		}
+
+		*arguments[(*n_arguments)++] = t;
+	}
+
+	if (ferror(f)) {
+		r = -EIO;
+		log_error("Failed to read from file: %m");
+	}
+
+	fclose(f);
+
+	return r;
+}
+
 int main(int argc, char *argv[]) {
         struct dirent **de = NULL;
         int r = EXIT_FAILURE, n, i;
@@ -86,70 +150,21 @@ int main(int argc, char *argv[]) {
         for (i = 0; i < n; i++) {
                 int k;
                 char *fn;
-                FILE *f;
 
                 k = asprintf(&fn, "/etc/modules-load.d/%s", de[i]->d_name);
-                free(de[i]);
-
-                if (k < 0) {
+                if (k >= 0) {
+			struct stat st;
+
+			if (de[i]->d_type == DT_REG ||
+			    (stat(fn, &st) >= 0 && S_ISREG(st.st_mode)))
+				if (load_modules_from_file(fn, &arguments, &n_arguments, &n_allocated) < 0)
+					r = EXIT_FAILURE;
+			free(fn);
+		} else {
                         log_error("Failed to allocate file name.");
                         r = EXIT_FAILURE;
-                        continue;
-                }
-
-                f = fopen(fn, "re");
-                free(fn);
-
-                if (!f) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        log_error("Failed to open %s: %m", fn);
-                        r = EXIT_FAILURE;
-                        continue;
-                }
-
-                for (;;) {
-                        char line[LINE_MAX], *l, *t;
-
-                        if (!(fgets(line, sizeof(line), f)))
-                                break;
-
-                        l = strstrip(line);
-                        if (*l == '#' || *l == 0)
-                                continue;
-
-                        if (!(t = strdup(l))) {
-                                log_error("Failed to allocate module name.");
-                                continue;
-                        }
-
-                        if (n_arguments >= n_allocated) {
-                                char **a;
-                                unsigned m;
-
-                                m = MAX(16U, n_arguments*2);
-
-                                if (!(a = realloc(arguments, sizeof(char*) * (m+1)))) {
-                                        log_error("Failed to increase module array size.");
-                                        free(t);
-                                        r = EXIT_FAILURE;
-                                        continue;
-                                }
-
-                                arguments = a;
-                                n_allocated = m;
-                        }
-
-                        arguments[n_arguments++] = t;
-                }
-
-                if (ferror(f)) {
-                        r = EXIT_FAILURE;
-                        log_error("Failed to read from file: %m");
-                }
-
-                fclose(f);
+		}
+		free(de[i]);
         }
 
         free(de);
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index 0c3b88d..2b9ad90 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -775,7 +775,8 @@ static int scandir_filter(const struct dirent *d) {
                 return 0;
 
         if (d->d_type != DT_REG &&
-            d->d_type != DT_LNK)
+            d->d_type != DT_LNK &&
+	    d->d_type != DT_UNKNOWN)
                 return 0;
 
         return endswith(d->d_name, ".conf");
@@ -955,18 +956,19 @@ int main(int argc, char *argv[]) {
                         char *fn;
 
                         k = asprintf(&fn, "/etc/tmpfiles.d/%s", de[j]->d_name);
-                        free(de[j]);
-
-                        if (k < 0) {
+			if (k >= 0) {
+				struct stat st;
+
+				if (de[j]->d_type == DT_REG ||
+				    (stat(fn, &st) >= 0 && S_ISREG(st.st_mode)))
+					if (read_config_file(fn, true) < 0)
+						r = EXIT_FAILURE;
+				free(fn);
+			} else {
                                 log_error("Failed to allocate file name.");
                                 r = EXIT_FAILURE;
-                                continue;
                         }
-
-                        if (read_config_file(fn, true) < 0)
-                                r = EXIT_FAILURE;
-
-                        free(fn);
+                        free(de[j]);
                 }
 
                 free(de);
diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c
index a9d06ac..3025102 100644
--- a/src/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent.c
@@ -507,8 +507,12 @@ static int show_passwords(void) {
                 int q;
                 char *wall;
 
-                if (de->d_type != DT_REG)
-                        continue;
+                if (de->d_type != DT_REG) {
+			struct stat st;
+
+			if (de->d_type != DT_UNKNOWN || fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0 || !S_ISREG(st.st_mode))
+					continue;
+		}
 
                 if (ignore_file(de->d_name))
                         continue;
-- 
tg: (fc7a744..) upstream/dt_unknown (depends on: origin/master)


More information about the systemd-devel mailing list