[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