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: tolzm...@molgen.mpg.de Signed-off-by: Andrey Borzenkov <arvidj...@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) _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel