Blame SOURCES/rsyslog-7.4.7-rhbz1245194-imjournal-ste-file.patch

14695b
From fed69cc7ac1bccb7012a68d954b58c6de9ad75e7 Mon Sep 17 00:00:00 2001
14695b
From: Tomas Heinrich <theinric@redhat.com>
14695b
Date: Sun, 10 Jul 2016 23:46:42 +0200
14695b
Subject: [PATCH] Make state file handling in imjournal more robust
14695b
14695b
---
14695b
 plugins/imjournal/imjournal.c | 98 ++++++++++++++++++++++++++++++-------------
14695b
 1 file changed, 70 insertions(+), 28 deletions(-)
14695b
14695b
diff --git a/plugins/imjournal/imjournal.c b/plugins/imjournal/imjournal.c
14695b
index f97b745..1ebbd1c 100755
14695b
--- a/plugins/imjournal/imjournal.c
14695b
+++ b/plugins/imjournal/imjournal.c
14695b
@@ -70,6 +70,7 @@ static struct configSettings_s {
14695b
 	int ratelimitInterval;
14695b
 	int ratelimitBurst;
14695b
 	int bIgnorePrevious;
14695b
+	int bIgnoreNonValidStatefile;
14695b
 	int iDfltSeverity;
14695b
 	int iDfltFacility;
14695b
 	char *dfltTag;
14695b
@@ -84,6 +85,7 @@ static struct cnfparamdescr modpdescr[] = {
14695b
 	{ "ratelimit.burst", eCmdHdlrInt, 0 },
14695b
 	{ "persiststateinterval", eCmdHdlrInt, 0 },
14695b
 	{ "ignorepreviousmessages", eCmdHdlrBinary, 0 },
14695b
+	{ "ignorenonvalidstatefile", eCmdHdlrBinary, 0 },
14695b
 	{ "defaultseverity", eCmdHdlrSeverity, 0 },
14695b
 	{ "defaultfacility", eCmdHdlrString, 0 },
14695b
 	{ "defaulttag", eCmdHdlrGetWord, 0 },
14695b
@@ -441,23 +443,36 @@ static rsRetVal
14695b
 persistJournalState () {
14695b
 	DEFiRet;
14695b
 	FILE *sf; /* state file */
14695b
+	char tmp_sf[MAXFNAME];
14695b
 	char *cursor;
14695b
 	int ret = 0;
14695b
 
14695b
 	/* On success, sd_journal_get_cursor()  returns 1 in systemd
14695b
 	   197 or older and 0 in systemd 198 or newer */
14695b
 	if ((ret = sd_journal_get_cursor(j, &cursor)) >= 0) {
14695b
-		if ((sf = fopen(cs.stateFile, "wb")) != NULL) {
14695b
+		/* we create a temporary name by adding a ".tmp"
14695b
+		 * suffix to the end of our state file's name
14695b
+		 */
14695b
+		snprintf(tmp_sf, sizeof(tmp_sf), "%s.tmp", cs.stateFile);
14695b
+		if ((sf = fopen(tmp_sf, "wb")) != NULL) {
14695b
 			if (fprintf(sf, "%s", cursor) < 0) {
14695b
 				iRet = RS_RET_IO_ERROR;
14695b
 			}
14695b
 			fclose(sf);
14695b
 			free(cursor);
14695b
+			/* change the name of the file to the configured one */
14695b
+			if (iRet == RS_RET_OK && rename(tmp_sf, cs.stateFile) == -1) {
14695b
+				char errStr[256];
14695b
+				rs_strerror_r(errno, errStr, sizeof(errStr));
14695b
+				iRet = RS_RET_IO_ERROR;
14695b
+				errmsg.LogError(0, iRet, "rename() failed: "
14695b
+					"'%s', new path: '%s'\n", errStr, cs.stateFile);
14695b
+			}
14695b
 		} else {
14695b
 			char errStr[256];
14695b
 			rs_strerror_r(errno, errStr, sizeof(errStr));
14695b
 			errmsg.LogError(0, RS_RET_FOPEN_FAILURE, "fopen() failed: "
14695b
-				"'%s', path: '%s'\n", errStr, cs.stateFile);
14695b
+				"'%s', path: '%s'\n", errStr, tmp_sf);
14695b
 			iRet = RS_RET_FOPEN_FAILURE;
14695b
 		}
14695b
 	} else {
14695b
@@ -515,6 +530,35 @@ finalize_it:
14695b
 	RETiRet;
14695b
 }
14695b
 
14695b
+/* Seek to the very end of the journal and ignore all older
14695b
+ * messages.
14695b
+ */
14695b
+static rsRetVal
14695b
+skipOldMessages(void)
14695b
+{
14695b
+	DEFiRet;
14695b
+
14695b
+	if (sd_journal_seek_tail(j) < 0) {
14695b
+		char errStr[256];
14695b
+
14695b
+		rs_strerror_r(errno, errStr, sizeof(errStr));
14695b
+		errmsg.LogError(0, RS_RET_ERR,
14695b
+			"sd_journal_seek_tail() failed: '%s'", errStr);
14695b
+		ABORT_FINALIZE(RS_RET_ERR);
14695b
+        }
14695b
+	if (sd_journal_previous(j) < 0) {
14695b
+		char errStr[256];
14695b
+
14695b
+		rs_strerror_r(errno, errStr, sizeof(errStr));
14695b
+		errmsg.LogError(0, RS_RET_ERR,
14695b
+			"sd_journal_previous() failed: '%s'", errStr);
14695b
+		ABORT_FINALIZE(RS_RET_ERR);
14695b
+	}
14695b
+
14695b
+finalize_it:
14695b
+	RETiRet;
14695b
+
14695b
+}
14695b
 
14695b
 /* This function loads a journal cursor from the state file.
14695b
  */
14695b
@@ -546,41 +590,32 @@ loadJournalState()
14695b
 					errmsg.LogError(0, RS_RET_ERR, "imjournal: "
14695b
 						"couldn't seek to cursor `%s'\n", readCursor);
14695b
 					iRet = RS_RET_ERR;
14695b
-					goto finalize_it;
14695b
+				} else {
14695b
+					sd_journal_next(j);
14695b
 				}
14695b
-				sd_journal_next(j);
14695b
 			} else {
14695b
 				errmsg.LogError(0, RS_RET_IO_ERROR, "imjournal: "
14695b
 					"fscanf on state file `%s' failed\n", cs.stateFile);
14695b
 				iRet = RS_RET_IO_ERROR;
14695b
-				goto finalize_it;
14695b
 			}
14695b
+
14695b
 			fclose(r_sf);
14695b
+
14695b
+			if (iRet != RS_RET_OK && cs.bIgnoreNonValidStatefile) {
14695b
+				/* ignore state file errors */
14695b
+				iRet = RS_RET_OK;
14695b
+				errmsg.LogError(0, NO_ERRCODE,
14695b
+					"imjournal: ignoring invalid state file");
14695b
+				if (cs.bIgnorePrevious) {
14695b
+					skipOldMessages();
14695b
+				}
14695b
+			}
14695b
 		} else {
14695b
 			errmsg.LogError(0, RS_RET_FOPEN_FAILURE, "imjournal: "
14695b
 					"open on state file `%s' failed\n", cs.stateFile);
14695b
 		}
14695b
-	} else {
14695b
-		/* when IgnorePrevious, seek to the end of journal */
14695b
-		if (cs.bIgnorePrevious) {
14695b
-			if (sd_journal_seek_tail(j) < 0) {
14695b
-				char errStr[256];
14695b
-
14695b
-				rs_strerror_r(errno, errStr, sizeof(errStr));
14695b
-				errmsg.LogError(0, RS_RET_ERR,
14695b
-					"sd_journal_seek_tail() failed: '%s'", errStr);
14695b
-				ABORT_FINALIZE(RS_RET_ERR);
14695b
-			}
14695b
-
14695b
-			if (sd_journal_previous(j) < 0) {
14695b
-				char errStr[256];
14695b
-
14695b
-				rs_strerror_r(errno, errStr, sizeof(errStr));
14695b
-				errmsg.LogError(0, RS_RET_ERR,
14695b
-					"sd_journal_previous() failed: '%s'", errStr);
14695b
-				ABORT_FINALIZE(RS_RET_ERR);
14695b
-			}
14695b
-		}
14695b
+	} else if (cs.bIgnorePrevious) {
14695b
+		skipOldMessages();
14695b
 	} 
14695b
 
14695b
 finalize_it:
14695b
@@ -598,6 +633,8 @@ CODESTARTrunInput
14695b
 
14695b
 	if (cs.stateFile) {
14695b
 		CHKiRet(loadJournalState());
14695b
+	} else if (cs.bIgnorePrevious) {
14695b
+		skipOldMessages();
14695b
 	}
14695b
 
14695b
 	/* this is an endless loop - it is terminated when the thread is
14695b
@@ -641,6 +678,7 @@ BEGINbeginCnfLoad
14695b
 CODESTARTbeginCnfLoad
14695b
 	bLegacyCnfModGlobalsPermitted = 1;
14695b
 
14695b
+	cs.bIgnoreNonValidStatefile = 1;
14695b
 	cs.iPersistStateInterval = DFLT_persiststateinterval;
14695b
 	cs.stateFile = NULL;
14695b
 	cs.ratelimitBurst = 20000;
14695b
@@ -739,7 +777,9 @@ CODESTARTsetModCnf
14695b
 		} else if(!strcmp(modpblk.descr[i].name, "ratelimit.interval")) {
14695b
 			cs.ratelimitInterval = (int) pvals[i].val.d.n;
14695b
 		} else if (!strcmp(modpblk.descr[i].name, "ignorepreviousmessages")) {
14695b
-			cs.bIgnorePrevious = (int) pvals[i].val.d.n; 
14695b
+			cs.bIgnorePrevious = (int) pvals[i].val.d.n;
14695b
+		} else if (!strcmp(modpblk.descr[i].name, "ignorenonvalidstatefile")) {
14695b
+			cs.bIgnoreNonValidStatefile = (int) pvals[i].val.d.n;
14695b
 		} else if (!strcmp(modpblk.descr[i].name, "defaultseverity")) {
14695b
 			cs.iDfltSeverity = (int) pvals[i].val.d.n;
14695b
 		} else if (!strcmp(modpblk.descr[i].name, "defaultfacility")) {
14695b
@@ -806,7 +846,9 @@ CODEmodInit_QueryRegCFSLineHdlr
14695b
 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalstatefile", 0, eCmdHdlrGetWord,
14695b
 		NULL, &cs.stateFile, STD_LOADABLE_MODULE_ID));
14695b
 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalignorepreviousmessages", 0, eCmdHdlrBinary,
14695b
-		NULL, &cs.bIgnorePrevious, STD_LOADABLE_MODULE_ID)); 
14695b
+		NULL, &cs.bIgnorePrevious, STD_LOADABLE_MODULE_ID));
14695b
+	CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournalignorenonvalidstatefile", 0, eCmdHdlrBinary,
14695b
+		NULL, &cs.bIgnoreNonValidStatefile, STD_LOADABLE_MODULE_ID));
14695b
 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournaldefaultseverity", 0, eCmdHdlrSeverity,
14695b
 		NULL, &cs.iDfltSeverity, STD_LOADABLE_MODULE_ID));
14695b
 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"imjournaldefaultfacility", 0, eCmdHdlrCustomHandler,
14695b
-- 
14695b
2.5.5
14695b