aboutsummaryrefslogtreecommitdiff
path: root/src/librc
diff options
context:
space:
mode:
authorAlexander Maltsev <keltar.gw@gmail.com>2023-11-12 12:29:22 +0500
committerWilliam Hubbs <w.d.hubbs@gmail.com>2023-11-14 14:35:23 -0600
commitfda9dcd1f2421f3ff1a366aa75f14e0141e754c5 (patch)
tree285103f5542313fb1a21a51e84c42a5228fe8cba /src/librc
parent6f180e94243885d312004ed89901329bd1a3ceb6 (diff)
Skip already processed files in rc_service_daemon_set
Fixes the problem described in https://bugs.gentoo.org/916947 - start-stop-daemon hangs in infinite loop when stopping some daemons on linux 6.6+ It appears linux 6.6 reworked tmpfs, and since then it triggers this problem in openrc: when iterating over files via readdir, running rename on a file could result in reading the same file again with next readdir call. The Open Group manual for readdir explicitly states "If a file is removed from or added to the directory after the most recent call to opendir() or rewinddir(), whether a subsequent call to readdir() returns an entry for that file is unspecified.". Linux man page don't seem to mention that, but don't seem to say anything to contradict that either. So I presume we can't rely on some specific behaviour here. Bug: https://bugs.gentoo.org/916947
Diffstat (limited to 'src/librc')
-rw-r--r--src/librc/librc-daemon.c12
1 files changed, 11 insertions, 1 deletions
diff --git a/src/librc/librc-daemon.c b/src/librc/librc-daemon.c
index 50245129..e23593b9 100644
--- a/src/librc/librc-daemon.c
+++ b/src/librc/librc-daemon.c
@@ -402,7 +402,7 @@ rc_service_daemon_set(const char *service, const char *exec,
bool retval = false;
DIR *dp;
struct dirent *d;
- RC_STRINGLIST *match;
+ RC_STRINGLIST *match, *renamelist;
int i = 0;
FILE *fp;
@@ -416,11 +416,17 @@ rc_service_daemon_set(const char *service, const char *exec,
/* Regardless, erase any existing daemon info */
if ((dp = opendir(dirpath))) {
match = _match_list(exec, argv, pidfile);
+ renamelist = rc_stringlist_new();
while ((d = readdir(dp))) {
if (d->d_name[0] == '.')
continue;
xasprintf(&file, "%s/%s", dirpath, d->d_name);
+ if (rc_stringlist_find(renamelist, file)) {
+ free(file);
+ continue;
+ }
+
nfiles++;
if (!*oldfile) {
@@ -432,11 +438,15 @@ rc_service_daemon_set(const char *service, const char *exec,
} else {
rename(file, oldfile);
strlcpy(oldfile, file, sizeof(oldfile));
+ /* Add renamed file to renamelist, as this new file name could
+ * be read again from readdir() */
+ rc_stringlist_add(renamelist, oldfile);
}
free(file);
}
closedir(dp);
rc_stringlist_free(match);
+ rc_stringlist_free(renamelist);
}
/* Now store our daemon info */