File logrotate-3.8.7-recover-from-corrupted-state-file.patch of Package logrotate.5563
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(-)
Index: logrotate-3.8.7/logrotate.c
===================================================================
--- logrotate-3.8.7.orig/logrotate.c
+++ logrotate-3.8.7/logrotate.c
@@ -181,23 +181,17 @@ static void unescape(char *arg)
}
#define HASH_SIZE_MIN 64
-static int allocateHash(void)
+static int allocateHash(unsigned int hs)
{
- struct logInfo *log;
- unsigned int hs;
int i;
- hs = 0;
-
- for (log = logs.tqh_first; log != NULL; log = log->list.tqe_next)
- hs += log->numFiles;
-
- hs *= 2;
-
/* Enforce some reasonable minimum hash size */
if (hs < HASH_SIZE_MIN)
hs = HASH_SIZE_MIN;
+ message(MESS_DEBUG, "Allocating hash table for state file, size %d entries\n",
+ hs);
+
states = calloc(hs, sizeof(struct logStates *));
if (states == NULL) {
message(MESS_ERROR, "could not allocate memory for "
@@ -2009,7 +2003,7 @@ static int readState(char *stateFilename
{
FILE *f;
char buf[STATEFILE_BUFFER_SIZE];
- char *filename;
+ char *filename;
const char **argv;
int argc;
int year, month, day, hour, minute, second;
@@ -2019,27 +2013,50 @@ static int readState(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);
- return 0;
- } else if (error) {
- message(MESS_ERROR, "error stat()ing state file %s: %s\n",
- stateFilename, strerror(errno));
- 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));
+
+ /* 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) {
message(MESS_ERROR, "error opening state file %s: %s\n",
@@ -2091,7 +2108,7 @@ static int readState(char *stateFilename
}
/* Hack to hide earlier bug */
- if ((year != 1900) && (year < 1996 || year > 2100)) {
+ if ((year != 1900) && (year < 1970 || year > 2100)) {
message(MESS_ERROR,
"bad year %d for file %s in state file %s\n", year,
argv[0], stateFilename);
@@ -2256,11 +2273,8 @@ int main(int argc, const char **argv)
poptFreeContext(optCon);
nowSecs = time(NULL);
- if (allocateHash() != 0)
- return 1;
-
- if (readState(stateFile))
- exit(1);
+ if (readState(stateFile))
+ rc = 1;
message(MESS_DEBUG, "\nHandling %d logs\n", numLogs);
Index: logrotate-3.8.7/test/test
===================================================================
--- logrotate-3.8.7.orig/test/test
+++ logrotate-3.8.7/test/test
@@ -1147,7 +1147,7 @@ fi
rm -f error.log
checkoutput <<EOF
-test.log 0 zero
+test.log 0
EOF