Blob Blame History Raw
From fed69cc7ac1bccb7012a68d954b58c6de9ad75e7 Mon Sep 17 00:00:00 2001
From: Tomas Heinrich <theinric@redhat.com>
Date: Sun, 10 Jul 2016 23:46:42 +0200
Subject: [PATCH] Make state file handling in imjournal more robust

---
 plugins/imjournal/imjournal.c | 98 ++++++++++++++++++++++++++++++-------------
 1 file changed, 70 insertions(+), 28 deletions(-)

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