summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Engelmayer2011-10-28 18:12:42 +0200
committerDenys Vlasenko2011-10-28 18:12:42 +0200
commit8de2e42201bb1b9054861d2f7645885a3b69642a (patch)
tree6bd55c55efe6777fbee54fe4a619afe1c83cea22
parente6094d95b5d5a1a4c76aff99d89c8a4f44c5d59a (diff)
downloadbusybox-8de2e42201bb1b9054861d2f7645885a3b69642a.zip
busybox-8de2e42201bb1b9054861d2f7645885a3b69642a.tar.gz
syslogd: work around rename() not renaming hardlinks to themselves
Function log_locally() within the syslogd can potentially lock up when restarting the daemon after a power loss in case the unplanned shutdown hit the rename operation during logfile rotation. While POSIX requires the rename operation to be atomic, many file systems such as JFFS2 implement the rename operation in 2 steps by linking the new name followed by unlinking the original name. In case of a power loss during the rename the system can end up with /var/log/messages and /var/log/messages.0 being 2 hard links to the same file. When the syslog daemon restarts in such a situation it will rediscover the need to rotate the log files, however, POSIX also requires that rename does nothing and reports success in case oldpath and newpath are existing hard links to the same file. Looping through reopen: by (O_CREAT | O_APPEND), the daemon eternally reopens the same file without succeeding to rotate. Signed-off-by: Christian Engelmayer <christian.engelmayer@frequentis.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--sysklogd/syslogd.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index d36d09c..fc380d9 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -594,6 +594,14 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file)
}
/* newFile == "f.0" now */
rename(log_file->path, newFile);
+ /* Incredibly, if F and F.0 are hardlinks, POSIX
+ * _demands_ that rename returns 0 but does not
+ * remove F!!!
+ * (hardlinked F/F.0 pair was observed after
+ * power failure during rename()).
+ * Ensure old file is gone:
+ */
+ unlink(log_file->path);
#ifdef SYSLOGD_WRLOCK
fl.l_type = F_UNLCK;
fcntl(log_file->fd, F_SETLKW, &fl);