File logrotate-3.11.0-recover-from-corrupted-state-file.patch of Package logrotate.10250
From b9d82003002c98370e4131a7e43c76afcd23306a Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@redhat.com>
Date: Wed, 8 Feb 2017 15:39:47 +0100
Subject: [PATCH] do not treat failure of readState() as fatal
This also prevents an empty state file from being written when running
with the --debug option.
Closes #45
---
logrotate.c | 68 +++++++++++++++++++++++++++++++++++--------------------------
test/test | 5 ++---
2 files changed, 41 insertions(+), 32 deletions(-)
diff --git a/logrotate.c b/logrotate.c
index 5709ab4..55ab74d 100644
--- a/logrotate.c
+++ b/logrotate.c
@@ -2333,32 +2333,49 @@ static int readState(const char *stateFilename)
struct logState *st;
time_t lr_time;
struct stat f_stat;
+ int rc = 0;
message(MESS_DEBUG, "Reading state from file: %s\n", stateFilename);
error = stat(stateFilename, &f_stat);
+ if (error) {
+ /* treat non-statable file as an empty file */
+ f_stat.st_size = 0;
+ if (errno != ENOENT) {
+ message(MESS_ERROR, "error stat()ing state file %s: %s\n",
+ stateFilename, strerror(errno));
+
+ /* do not return until the hash table is allocated */
+ rc = 1;
+ }
+ }
- if ((error && errno == ENOENT) || (!error && f_stat.st_size == 0)) {
- /* create the file before continuing to ensure we have write
- access to the file */
- f = fopen(stateFilename, "w");
- if (!f) {
- message(MESS_ERROR, "error creating state file %s: %s\n",
- stateFilename, strerror(errno));
- return 1;
- }
- fprintf(f, "logrotate state -- version 2\n");
- fclose(f);
-
- if (allocateHash(64) != 0)
- return 1;
+ if (!debug && (f_stat.st_size == 0)) {
+ /* create the file before continuing to ensure we have write
+ access to the file */
+ f = fopen(stateFilename, "w");
+ if (f) {
+ fprintf(f, "logrotate state -- version 2\n");
+ fclose(f);
+ } else {
+ message(MESS_ERROR, "error creating state file %s: %s\n",
+ stateFilename, strerror(errno));
- return 0;
- } else if (error) {
- message(MESS_ERROR, "error stat()ing state file %s: %s\n",
- stateFilename, strerror(errno));
- return 1;
+ /* do not return until the hash table is allocated */
+ rc = 1;
}
+ }
+
+ /* Try to estimate how many state entries we have in the state file.
+ * We expect single entry to have around 80 characters (Of course this is
+ * just an estimation). During the testing I've found out that 200 entries
+ * per single hash entry gives good mem/performance ratio. */
+ if (allocateHash(f_stat.st_size / 80 / 200))
+ return 1;
+
+ if (rc || (f_stat.st_size == 0))
+ /* error already occurred, or we have no state file to read from */
+ return rc;
f = fopen(stateFilename, "r");
if (!f) {
@@ -2382,13 +2399,6 @@ static int readState(const char *stateFilename)
return 1;
}
- /* Try to estimate how many state entries we have in the state file.
- * We expect single entry to have around 80 characters (Of course this is
- * just an estimation). During the testing I've found out that 200 entries
- * per single hash entry gives good mem/performance ratio. */
- if (allocateHash(f_stat.st_size / 80 / 200) != 0)
- return 1;
-
line++;
while (fgets(buf, sizeof(buf) - 1, f)) {
@@ -2603,10 +2613,10 @@ int main(int argc, const char **argv)
poptFreeContext(optCon);
nowSecs = time(NULL);
- if (readState(stateFile))
- exit(1);
+ if (readState(stateFile))
+ rc = 1;
- message(MESS_DEBUG, "\nHandling %d logs\n", numLogs);
+ message(MESS_DEBUG, "\nHandling %d logs\n", numLogs);
for (log = logs.tqh_first; log != NULL; log = log->list.tqe_next)
rc |= rotateLogSet(log, force);
diff --git a/test/test b/test/test
index 8de30ea..a0b51ee 100755
--- a/test/test
+++ b/test/test
@@ -1188,8 +1188,7 @@ EOF
cleanup 46
# ------------------------------- Test 46 ------------------------------------
-# the state file is truncated and obviously corrupt, so no rotation should
-# happen
+# the state file is truncated and obviously corrupt
preptest test.log 46 1
cat > state << EOF
@@ -1210,7 +1209,7 @@ fi
rm -f error.log
checkoutput <<EOF
-test.log 0 zero
+test.log 0
EOF