From 139c61a9007600c93702947179d7836be1bc8403 Mon Sep 17 00:00:00 2001
From: burnalting <burnalting@users.noreply.github.com>
Date: Thu, 11 Jan 2024 08:22:32 +1100
Subject: [PATCH] Issue343: Fix checkpoint issue to ensure all complete events
 are gained (#345)

Co-authored-by: Burn Alting <burn@auditdtest.swtf.dyndns.org>

Reference:https://github.com/linux-audit/audit-userspace/commit/139c61a9007600c93702947179d7836be1bc8403
Conflict:NA

---
 src/ausearch-lol.c | 33 +++++++++++++++++++++++++++++++++
 src/ausearch-lol.h |  1 +
 src/ausearch.c     | 12 +++++++-----
 3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/src/ausearch-lol.c b/src/ausearch-lol.c
index 9ed39d4f..bcfb9ad8 100644
--- a/src/ausearch-lol.c
+++ b/src/ausearch-lol.c
@@ -261,6 +261,32 @@ static void check_events(lol *lo, time_t sec)
 	}
 }
 
+// This function will check events to see if they are complete but not compare against a given time
+static void check_events_without_time(lol *lo)
+{
+	int i;
+
+	for(i=0;i<=lo->maxi; i++) {
+		lolnode *cur = &lo->array[i];
+		if (cur->status == L_BUILDING) {
+			/* We now iterate over the event's records but without affecting the node's current
+			 * pointer (cur->l->cur). That is, we don't call the list-* routines
+			 * We could jump to the last record in the list which is normally a PROCTITLE, but this
+			 * may not be guaranteed, so we check all record types
+			 */
+			lnode *ln = cur->l->head;
+			while (ln) {
+				if (audit_is_last_record(ln->type)) {
+					cur->status = L_COMPLETE;
+					ready++;
+					break;
+				}
+				ln = ln->next;
+			}
+		}
+	}
+}
+
 // This function adds a new record to an existing linked list
 // or creates a new one if its a new event
 int lol_add_record(lol *lo, char *buff)
@@ -360,6 +386,13 @@ void terminate_all_events(lol *lo)
 	}
 }
 
+// This function will mark all events as complete if it can.
+void complete_all_events(lol *lo)
+{
+
+	check_events_without_time(lo);
+}
+
 /* Search the list for any event that is ready to go. The caller
  * takes custody of the memory */
 llist* get_ready_event(lol *lo)
diff --git a/src/ausearch-lol.h b/src/ausearch-lol.h
index e189491e..427d083c 100644
--- a/src/ausearch-lol.h
+++ b/src/ausearch-lol.h
@@ -49,6 +49,7 @@ void lol_create(lol *lo);
 void lol_clear(lol *lo);
 int lol_add_record(lol *lo, char *buff);
 void terminate_all_events(lol *lo);
+void complete_all_events(lol *lo);
 llist* get_ready_event(lol *lo);
 
 void lol_set_eoe_timeout(time_t new_eoe_tmo);
diff --git a/src/ausearch.c b/src/ausearch.c
index c8cafb5f..409e43e9 100644
--- a/src/ausearch.c
+++ b/src/ausearch.c
@@ -610,19 +610,21 @@ static int get_next_event(llist **l)
 			 * If we get an EINTR error or we are at EOF, we check
 			 * to see if we have any events to print and return
 			 * appropriately. If we are the last file being
-			 * processed, we mark all incomplete events as
-			 * complete so they will be printed.
+			 * processed, and we are not checkpointing, we mark all incomplete
+			 * events as complete so they will be printed. If we are checkpointing
+			 * we do an exhaustive validation to see if there are complete events still
 			 */
 			if ((ferror_unlocked(log_fd) &&
 			     errno == EINTR) || feof_unlocked(log_fd)) {
 				/*
-				 * Only mark all events as L_COMPLETE if we are
+				 * Only attempt to mark all events as L_COMPLETE if we are
 				 * the last file being processed.
-				 * We DO NOT do this if we are checkpointing.
 				 */
 				if (files_to_process == 0) {
 					if (!checkpt_filename)
-					terminate_all_events(&lo);
+					 	terminate_all_events(&lo);	// terminate as we are not checkpointing
+					else
+					 	complete_all_events(&lo);	// exhaustively check if we can complete events
 				}
 				*l = get_ready_event(&lo);
 				if (*l)
-- 
2.33.0

