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
 
 
openSUSE Build Service is sponsored by