From a938df43f385f8cc85e032a5459247423c2d9ed2 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:16:07 +0530 Subject: [PATCH 1/4] Update dcautil.c --- source/dcautil/dcautil.c | 144 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 5f7185c63..bc654c8b2 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -19,7 +19,13 @@ #include #include +#include +#include +#include #include +#include +#include +#include #include "dca.h" #include "dcautil.h" #include "telemetry2_0.h" @@ -28,6 +34,130 @@ #include "legacyutils.h" #include "persistence.h" +/** + * @brief Wait for the backup_logs completion sentinel before grepping PreviousLogs. + * + * Strategy: + * 1. Fast path: sentinel already present → return true immediately. + * 2. Set up inotify on BACKUP_LOGS_DONE_DIR (/tmp) for IN_CREATE | IN_MOVED_TO. + * 3. Re-check after watch is established to close the creation race window. + * 4. select() loop with 2 s heartbeat; exit when sentinel appears or + * BACKUP_LOGS_SYNC_TIMEOUT_S total seconds have elapsed. + * + * This is a **soft gate**: if the function returns false (timeout or inotify + * failure) the caller still proceeds — previous-log grep runs against whatever + * files are present, and a warning is logged. + * + * @return true sentinel detected within timeout + * @return false timeout elapsed or inotify initialisation failed + */ +static bool waitForBackupLogsDone(void) +{ + /* Fast path: sentinel already written by backup_logs */ + if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) + { + T2Info("backup_logs sentinel %s already present\n", BACKUP_LOGS_DONE_FLAG); + return true; + } + + int ifd = inotify_init1(IN_CLOEXEC); + if (ifd < 0) + { + T2Error("inotify_init1 failed (errno=%d); proceeding without backup_logs sync\n", errno); + return false; + } + + int wd = inotify_add_watch(ifd, BACKUP_LOGS_DONE_DIR, IN_CREATE | IN_MOVED_TO); + if (wd < 0) + { + T2Error("inotify_add_watch on %s failed (errno=%d); proceeding without backup_logs sync\n", + BACKUP_LOGS_DONE_DIR, errno); + close(ifd); + return false; + } + + /* Re-check after watch is set — closes the race window between the first + * access() call and establishing the watch. */ + if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) + { + T2Info("backup_logs sentinel detected (race resolved): %s\n", BACKUP_LOGS_DONE_FLAG); + inotify_rm_watch(ifd, wd); + close(ifd); + return true; + } + + struct timespec deadline; + if (clock_gettime(CLOCK_MONOTONIC, &deadline) != 0) + { + T2Error("clock_gettime failed (errno=%d); proceeding without backup_logs sync\n", errno); + inotify_rm_watch(ifd, wd); + close(ifd); + return false; + } + deadline.tv_sec += BACKUP_LOGS_SYNC_TIMEOUT_S; + + T2Info("Waiting up to %ds for backup_logs sentinel: %s\n", + BACKUP_LOGS_SYNC_TIMEOUT_S, BACKUP_LOGS_DONE_FLAG); + + bool found = false; + char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; + + while (!found) + { + /* Check deadline */ + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) == 0 && now.tv_sec >= deadline.tv_sec) + { + T2Warning("backup_logs sentinel not present after %ds; proceeding without sync\n", + BACKUP_LOGS_SYNC_TIMEOUT_S); + break; + } + + struct timeval tv = {2, 0}; + fd_set fds; + FD_ZERO(&fds); + FD_SET(ifd, &fds); + + int ret = select(ifd + 1, &fds, NULL, NULL, &tv); + if (ret < 0) + { + if (errno == EINTR) + { + continue; + } + T2Error("select() failed (errno=%d) waiting for backup_logs sentinel\n", errno); + break; + } + if (ret == 0) + { + continue; /* 2 s heartbeat — loop back to check deadline */ + } + + ssize_t len = read(ifd, buf, sizeof(buf)); + if (len <= 0) + { + continue; + } + + ssize_t offset = 0; + while (offset < len) + { + struct inotify_event *ev = (struct inotify_event *)(buf + offset); + if (ev->len > 0 && strcmp(ev->name, BACKUP_LOGS_DONE_FILENAME) == 0) + { + T2Info("backup_logs sentinel created: %s\n", BACKUP_LOGS_DONE_FLAG); + found = true; + break; + } + offset += (ssize_t)(sizeof(struct inotify_event) + ev->len); + } + } + + inotify_rm_watch(ifd, wd); + close(ifd); + return found; +} + /** * @brief Get the Grep Results object. Main function called by rest of the consumers. * @@ -50,6 +180,20 @@ getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, return T2ERROR_FAILURE; } + /* Synchronize with backup_logs before grepping the previous-log directory. + * backup_logs populates PREVIOUS_LOGS_PATH; reading it before the write is + * complete yields incomplete or empty results. This is a soft gate — if the + * sentinel does not appear within BACKUP_LOGS_SYNC_TIMEOUT_S seconds we + * still proceed so telemetry is never permanently blocked. */ + if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) + { + if (!waitForBackupLogsDone()) + { + T2Warning("%s: backup_logs sentinel absent; grepping %s with potentially incomplete data\n", + __FUNCTION__, PREVIOUS_LOGS_PATH); + } + } + getDCAResultsInVector(*GSP, markerList, check_rotated, customLogPath); if (isClearSeekMap) { From 91620a656c6982efa91b4d039724132f6e6ef28b Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:16:57 +0530 Subject: [PATCH 2/4] Update dcautil.h --- source/dcautil/dcautil.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/dcautil/dcautil.h b/source/dcautil/dcautil.h index 73487672b..873d98348 100644 --- a/source/dcautil/dcautil.h +++ b/source/dcautil/dcautil.h @@ -35,6 +35,21 @@ #define PREVIOUS_LOGS_VAL "1" #define PREVIOUS_LOGS_PATH "/opt/logs/PreviousLogs/" +/** Sentinel written by dcm-agent backup_logs on successful completion. + * Telemetry waits for this file before grepping PREVIOUS_LOGS_PATH to + * guarantee the previous-log directory is fully populated. + * Cross-repo interface: also defined in dcm-agent backup_logs/include/backup_logs.h. + * Any path change MUST be coordinated with the dcm-agent repository. */ +#define BACKUP_LOGS_DONE_FLAG "/tmp/.backup_logs_done" +#define BACKUP_LOGS_DONE_DIR "/tmp" +#define BACKUP_LOGS_DONE_FILENAME ".backup_logs_done" + +#ifdef GTEST_ENABLE +# define BACKUP_LOGS_SYNC_TIMEOUT_S 2 +#else +# define BACKUP_LOGS_SYNC_TIMEOUT_S 60 +#endif + typedef struct _GrepResult { const char* markerName; From c7dbcff0e1c024fe03085ec27f8eb95aa467ca56 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Thu, 2 Jul 2026 17:37:27 +0530 Subject: [PATCH 3/4] Update dcautil.h --- source/dcautil/dcautil.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/source/dcautil/dcautil.h b/source/dcautil/dcautil.h index 873d98348..aacae9bcf 100644 --- a/source/dcautil/dcautil.h +++ b/source/dcautil/dcautil.h @@ -30,16 +30,11 @@ #define TOPTEMP "/tmp/t2toplog" #define DCADONEFLAG "/tmp/.dca_done" +#define TELEMETRY_PREVLOGS_DONE_FLAG "/tmp/.telemetry_prevlogs_done" #define PREVIOUS_LOG "PREVIOUS_LOG" #define PREVIOUS_LOGS_VAL "1" #define PREVIOUS_LOGS_PATH "/opt/logs/PreviousLogs/" - -/** Sentinel written by dcm-agent backup_logs on successful completion. - * Telemetry waits for this file before grepping PREVIOUS_LOGS_PATH to - * guarantee the previous-log directory is fully populated. - * Cross-repo interface: also defined in dcm-agent backup_logs/include/backup_logs.h. - * Any path change MUST be coordinated with the dcm-agent repository. */ #define BACKUP_LOGS_DONE_FLAG "/tmp/.backup_logs_done" #define BACKUP_LOGS_DONE_DIR "/tmp" #define BACKUP_LOGS_DONE_FILENAME ".backup_logs_done" From 878e4bdb0c1dce59be5172a3e17e1dc8bc47e15d Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 7 Jul 2026 10:35:01 +0530 Subject: [PATCH 4/4] Update dcautil.c --- source/dcautil/dcautil.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index bc654c8b2..91d2131be 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -201,7 +201,23 @@ getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, freeGrepSeekProfile(*GSP); *GSP = createGrepSeekProfile(count); } - + /* Signal that telemetry previous-log grep is complete. + * Downstream consumers (e.g. uploadSTBLogs) wait for this sentinel + * before starting the log upload to avoid incomplete telemetry data. */ + if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) + { + FILE *fp = fopen(TELEMETRY_PREVLOGS_DONE_FLAG, "w"); + if (fp != NULL) + { + fclose(fp); + T2Info("Created telemetry previous-logs sentinel: %s\n", TELEMETRY_PREVLOGS_DONE_FLAG); + } + else + { + T2Error("%s: Failed to create sentinel %s (errno=%d)\n", + __FUNCTION__, TELEMETRY_PREVLOGS_DONE_FLAG, errno); + } + } T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; }