summaryrefslogtreecommitdiffstats
path: root/runtime/srutils.c
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2010-04-09 13:00:56 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2010-04-09 13:00:56 +0200
commit8f0a8076cc8194036dbd4edca1c2c30a7822dd09 (patch)
treea7fd5bacf8d80fff628421186662d91705bdb8f1 /runtime/srutils.c
parentc1e3a032b447487ced9873b98a015046778d2b04 (diff)
parent87a957b0f5686ec3a50c98f3d1cf3019b636e700 (diff)
downloadrsyslog-8f0a8076cc8194036dbd4edca1c2c30a7822dd09.tar.gz
rsyslog-8f0a8076cc8194036dbd4edca1c2c30a7822dd09.tar.xz
rsyslog-8f0a8076cc8194036dbd4edca1c2c30a7822dd09.zip
Merge branch 'beta' into master
Conflicts: ChangeLog configure.ac plugins/imudp/imudp.c runtime/stream.h tests/Makefile.am tests/diag.sh tools/omfile.c
Diffstat (limited to 'runtime/srutils.c')
-rw-r--r--runtime/srutils.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/runtime/srutils.c b/runtime/srutils.c
index 2bed624e..d357cd77 100644
--- a/runtime/srutils.c
+++ b/runtime/srutils.c
@@ -169,10 +169,22 @@ uchar *srUtilStrDup(uchar *pOld, size_t len)
/* creates a path recursively
- * Return 0 on success, -1 otherwise. On failure, errno
- * hold the last OS error.
- * Param "mode" holds the mode that all non-existing directories
- * are to be created with.
+ * Return 0 on success, -1 otherwise. On failure, errno * hold the last OS error.
+ * Param "mode" holds the mode that all non-existing directories are to be
+ * created with.
+ * Note that we have a potential race inside that code, a race that even exists
+ * outside of the rsyslog process (if multiple instances run, or other programs
+ * generate directories): If the directory does not exist, a context switch happens,
+ * at that moment another process creates it, then our creation on the context
+ * switch back fails. This actually happened in practice, and depending on the
+ * configuration it is even likely to happen. We can not solve this situation
+ * with a mutex, as that works only within out process space. So the solution
+ * is that we take the optimistic approach, try the creation, and if it fails
+ * with "already exists" we go back and do one retry of the check/create
+ * sequence. That should then succeed. If the directory is still not found but
+ * the creation fails in the similar way, we return an error on that second
+ * try because otherwise we would potentially run into an endless loop.
+ * loop. -- rgerhards, 2010-03-25
*/
int makeFileParentDirs(uchar *szFile, size_t lenFile, mode_t mode,
uid_t uid, gid_t gid, int bFailOnChownFail)
@@ -180,6 +192,8 @@ int makeFileParentDirs(uchar *szFile, size_t lenFile, mode_t mode,
uchar *p;
uchar *pszWork;
size_t len;
+ int err;
+ int iTry = 0;
int bErr = 0;
assert(szFile != NULL);
@@ -193,8 +207,9 @@ int makeFileParentDirs(uchar *szFile, size_t lenFile, mode_t mode,
if(*p == '/') {
/* temporarily terminate string, create dir and go on */
*p = '\0';
+again:
if(access((char*)pszWork, F_OK)) {
- if(mkdir((char*)pszWork, mode) == 0) {
+ if((err = mkdir((char*)pszWork, mode)) == 0) {
if(uid != (uid_t) -1 || gid != (gid_t) -1) {
/* we need to set owner/group */
if(chown((char*)pszWork, uid, gid) != 0)
@@ -204,8 +219,13 @@ int makeFileParentDirs(uchar *szFile, size_t lenFile, mode_t mode,
* to do so.
*/
}
- } else
+ } else {
+ if(err == EEXIST && iTry == 0) {
+ iTry = 1;
+ goto again;
+ }
bErr = 1;
+ }
if(bErr) {
int eSave = errno;
free(pszWork);