diff --git a/README.md b/README.md index 4cc02cde..53fc053a 100644 --- a/README.md +++ b/README.md @@ -374,6 +374,10 @@ Sub-components within `uploadstblogs/`: | validation | `validation.h` | Parameter and path validation | | verification | `verification.h` | Post-upload result verification | +**RDK-C behaviors:** + +- **Scheduled log collection** — when `DCM_SCHEDULED_LOG_COLLECT=true` (`/etc/device.properties`, RDK-C only), `dcm_setup` stages the current `/opt/logs` tree into `DCM_LOG_PATH` (via `copy_files_to_dcm_path`) so the daily scheduled DCM upload carries current logs. Default **off** on STB/broadband (external batcher / Maintenance Manager supplies the logs). + --- ### backup\_logs — Log Backup @@ -525,6 +529,8 @@ make install | Flag | Effect | |------|--------| | `-DRDK_LOGGER_ENABLED` | Use RDK logger instead of stderr | +| `-DRDK_LOGGER_EXT` | Use the **extended** RDK logger init API (`rdk_logger_ext_config_t`, `RDKLOG_OUTPUT_CONSOLE`, `RDKLOG_FORMAT_WITH_TS`). Its **absence** makes `context_manager.c` fall back to the standard `rdk_logger_init(debug.ini)` — required for RDK-C, whose rdk-logger 2.4.0 predates the extended API. | +| `-DRDKC` | RDK-C (camera) platform marker. | | `-DHAS_MAINTENANCE_MANAGER` | Enable Maintenance Manager integration via IARM | | `-DGTEST_ENABLE` | Stub out RBUS/IARM for unit testing | | `-DDCM_DEF_LOG_URL=` | Override default fallback upload URL | @@ -608,6 +614,15 @@ if (ret != DCM_SUCCESS) { - Optional IARM bus integration for Maintenance Manager notifications. - RDK logger (`librdkloggers`) replaces `fprintf(stderr)` when available. +### RDK-C / Sysvinit (Camera) + +RDK-C camera platforms (e.g. XHC1) run **sysvinit**, not systemd, and ship an older rdk-logger. Key differences: + +- **No systemd** — the `sys_integration` systemd READY notification is inactive and `dcmd.service` is not installed; `dcmd` is started from the sysvinit `dcm-log-service` init script. +- **DCM–T2 handshake retry** — sysvinit start order is variable (telemetry can start well before `dcmd`), so the reload-config event publish is retried up to `DCM_RELOAD_EVENT_MAX_RETRY` (30 attempts, 1 s apart) so the handshake completes regardless of order. +- **Logger fallback** — built **without** `-DRDK_LOGGER_EXT` (see Conditional Compile Flags), so `context_manager.c` initialises logging via the standard `rdk_logger_init(debug.ini)` path. +- **Scheduled log collection** — `DCM_SCHEDULED_LOG_COLLECT=true` in `/etc/device.properties` stages the current `/opt/logs` tree into `DCM_LOG_PATH` before the scheduled DCM upload (RDK-C cameras have no external batcher). Default **off** on STB/broadband. + ### Resource Constraints | Resource | Typical Budget | diff --git a/Readme.txt b/Readme.txt index e69de29b..3d49fdda 100644 --- a/Readme.txt +++ b/Readme.txt @@ -0,0 +1,2 @@ +See README.md for the full DCM Agent documentation (architecture, modules, +build instructions, RDK-C / sysvinit platform notes, and testing). diff --git a/dcm.c b/dcm.c index bc48a85b..7c9f5acc 100755 --- a/dcm.c +++ b/dcm.c @@ -39,6 +39,14 @@ #include "dcm_schedjob.h" #include "uploadstblogs.h" +/* + * Max attempts to publish the reload config event to telemetry before giving up + * and continuing to the scheduling loop. Retrying makes the DCM<->T2 reload + * handshake independent of daemon start order (see the reload publish in main() + * and registerRbusDCMEventListener in telemetry's rbusInterface.c). + */ +#define DCM_RELOAD_EVENT_MAX_RETRY 30 + static DCMDHandle *g_pdcmHandle = NULL; /** @brief Call back function from Scheduler. This function @@ -345,7 +353,28 @@ int main(int argc, char* argv[]) DCMInfo("Telemetry Events subscriptions is success\n"); - ret = dcmRbusSendEvent(g_pdcmHandle->pRbusHandle); + /* + * Publish the reload event to telemetry. dcmRbusSendEvent only succeeds once + * telemetry has subscribed to the reload event; on RDK-C that subscribe can + * complete just after dcmd is ready, so the first publish may race ahead of + * it. Retry a bounded number of times until the event is delivered. The + * bound preserves the legacy "log and continue" behaviour so dcmd still + * enters its scheduling loop even if telemetry never subscribes. + */ + { + INT32 retryCount = 0; + do { + ret = dcmRbusSendEvent(g_pdcmHandle->pRbusHandle); + if(ret == DCM_SUCCESS) { + break; + } + retryCount++; + DCMInfo("Reload event not delivered yet, retry %d/%d\n", + retryCount, DCM_RELOAD_EVENT_MAX_RETRY); + sleep(1); + } while(retryCount < DCM_RELOAD_EVENT_MAX_RETRY); + } + if(ret) { DCMError("Reload config event failed!!!\n"); } @@ -409,7 +438,7 @@ int main(int argc, char* argv[]) #endif #ifdef GTEST_ENABLE -void get_dcmRunJobs(const INT8* profileName, VOID *pHandle) +void get_dcmRunJobs(const INT8* profileName, VOID *pHandle) { dcmRunJobs(profileName, pHandle); } diff --git a/docs/Logupload_Behavior/README.md b/docs/Logupload_Behavior/README.md index 4d2be467..7e7ccd84 100644 --- a/docs/Logupload_Behavior/README.md +++ b/docs/Logupload_Behavior/README.md @@ -1,7 +1,7 @@ # Log Upload Behavior in the RDKE Stack > **Explore mode document** — Researched from codebase and GitHub (rdkcentral/dcm-agent, -> rdkcentral/rdkservices, rdkcentral/reboot-manager, rdkcentral/telemetry, rdkcentral/iarmmgrs). +> rdkcentral/rdkservices, rdkcentral/reboot-manager, rdkcentral/telemetry, rdkcentral/iarmmgrs). > Date: 2026-05-20. --- @@ -12,6 +12,20 @@ This folder documents the full behavioral picture of log upload across the RDKE triggers it, what it does, what events it emits, which other components depend on its outputs, and how boot-time ordering is (or isn't) enforced. +--- + +## RDK-C (Camera) Additions + +On RDK-C camera platforms (sysvinit; e.g. XHC1), the DCM Agent runs as the native `dcmd` +daemon with an RDK-C-specific behavior layered onto the pipeline below: + +- **Scheduled log collection** (`DCM_SCHEDULED_LOG_COLLECT`) — RDK-C cameras have no external + batcher / Maintenance Manager, so with `DCM_SCHEDULED_LOG_COLLECT=true` in + `/etc/device.properties` the DCM strategy's `dcm_setup` stages the current `/opt/logs` tree + into `DCM_LOG_PATH` (via `copy_files_to_dcm_path`) before the scheduled upload, so the daily + archive carries current logs. Default **off** on STB/broadband (sources below supply the logs + externally). + --- ## RDKE Log Upload Support diff --git a/test/functional-tests/tests/test_uploadstblogs_upload_strategies.py b/test/functional-tests/tests/test_uploadstblogs_upload_strategies.py index 2b7991fa..84a64899 100644 --- a/test/functional-tests/tests/test_uploadstblogs_upload_strategies.py +++ b/test/functional-tests/tests/test_uploadstblogs_upload_strategies.py @@ -48,14 +48,14 @@ def setup_and_teardown(self): def test_ondemand_immediate_execution(self): """Test: On-demand upload executes immediately""" create_test_log_files(count=2) - + # Trigger on-demand upload (TriggerType=5) args = "'' 0 0 0 HTTP http://localhost:8080 5 0 ''" - + start_time = time.time() result = run_uploadstblogs(args) elapsed = time.time() - start_time - + # Should start immediately without waiting assert elapsed < 30, "On-demand upload should execute immediately" @@ -63,11 +63,11 @@ def test_ondemand_immediate_execution(self): def test_ondemand_no_schedule_wait(self): """Test: On-demand upload doesn't wait for scheduled time""" create_test_log_files(count=2) - + # Execute on-demand args = "'' 0 0 0 HTTP http://localhost:8080 5 0 ''" result = run_uploadstblogs(args) - + # Check logs for immediate execution immediate_logs = grep_uploadstb_logs_regex(r"immediate|ondemand|manual") # Process should complete @@ -77,10 +77,10 @@ def test_ondemand_no_schedule_wait(self): def test_ondemand_telemetry(self): """Test: On-demand upload generates appropriate telemetry""" create_test_log_files(count=1) - + args = "'' 0 0 0 HTTP http://localhost:8080 5 0 ''" result = run_uploadstblogs(args) - + # Check for telemetry telemetry_logs = grep_uploadstb_logs_regex(r"telemetry|marker") # Should complete @@ -105,12 +105,12 @@ def setup_and_teardown(self): def test_reboot_upload_detection(self): """Test: Service detects reboot condition""" create_test_log_files(count=2) - + # Trigger reboot upload (UploadOnReboot=1, TriggerType=2) args = "'' 0 0 1 HTTP http://localhost:8080 2 0 ''" - + result = run_uploadstblogs(args) - + # Check for reboot detection (may not be explicitly logged) reboot_logs = grep_uploadstb_logs_regex(r"reboot|UploadOnReboot|REBOOT|TriggerType.*2") # Process should complete with reboot parameters @@ -122,12 +122,12 @@ def test_reboot_previous_logs_collection(self): # Create files in PreviousLogs directory sp.run("mkdir -p /opt/logs/PreviousLogs", shell=True) sp.run("echo 'previous log content' > /opt/logs/PreviousLogs/prev.log", shell=True) - + create_test_log_files(count=1) - + args = "'' 0 0 1 HTTP http://localhost:8080 2 0 ''" result = run_uploadstblogs(args) - + # Check for previous log collection prev_logs = grep_uploadstb_logs_regex(r"previous|PreviousLogs") # Should process logs @@ -137,10 +137,10 @@ def test_reboot_previous_logs_collection(self): def test_reboot_upload_telemetry(self): """Test: Reboot upload generates appropriate telemetry""" create_test_log_files(count=1) - + args = "'' 0 0 1 HTTP http://localhost:8080 2 0 ''" result = run_uploadstblogs(args) - + # Check for telemetry telemetry_logs = grep_uploadstb_logs_regex(r"telemetry|reboot.*success") # Should complete @@ -165,12 +165,12 @@ def setup_and_teardown(self): def test_dcm_scheduled_trigger(self): """Test: DCM scheduled upload is triggered correctly""" create_test_log_files(count=2) - + # DCM scheduled upload (FLAG=0, DCM_FLAG=0, TriggerType=0) args = "'' 0 0 0 HTTP http://localhost:8080 0 0 ''" - + result = run_uploadstblogs(args) - + # Check for DCM processing dcm_logs = grep_uploadstb_logs_regex(r"DCM|scheduled|FLAG.*0") assert len(dcm_logs) > 0, "DCM scheduled upload should be processed" @@ -179,10 +179,10 @@ def test_dcm_scheduled_trigger(self): def test_dcm_log_collection(self): """Test: DCM scheduled upload collects logs according to configuration""" create_test_log_files(count=3) - + args = "'' 0 0 0 HTTP http://localhost:8080 0 0 ''" result = run_uploadstblogs(args) - + # Check for log collection collection_logs = grep_uploadstb_logs_regex(r"collect|archive|DCM") # Should attempt collection @@ -192,15 +192,47 @@ def test_dcm_log_collection(self): def test_dcm_upload_telemetry(self): """Test: DCM upload generates telemetry""" create_test_log_files(count=1) - + args = "'' 0 0 0 HTTP http://localhost:8080 0 0 ''" result = run_uploadstblogs(args) - + # Check telemetry telemetry_logs = grep_uploadstb_logs_regex(r"telemetry|marker|SYST") # Should complete assert result.returncode in [0, 1], "Should generate DCM telemetry" + @pytest.mark.order(4) + def test_dcm_scheduled_log_collect_enabled(self): + """RDK-C: DCM_SCHEDULED_LOG_COLLECT=true stages current logs into DCM_LOG_PATH.""" + set_device_property("DCM_SCHEDULED_LOG_COLLECT", "true") + create_test_log_files(count=3) + + args = "'' 0 0 0 HTTP http://localhost:8080 0 0 ''" + result = run_uploadstblogs(args) + + # The DCM strategy should log the RDK-C current-log collection step + collect_logs = grep_uploadstb_logs_regex( + r"Collecting current logs|Scheduled DCM log collection enabled|Successfully copied") + assert len(collect_logs) > 0, \ + "DCM_SCHEDULED_LOG_COLLECT=true should stage current logs into DCM_LOG_PATH" + assert result.returncode in [0, 1], "DCM upload should complete" + + @pytest.mark.order(5) + def test_dcm_scheduled_log_collect_disabled(self): + """RDK-C: without the flag the DCM strategy does NOT stage current logs (STB/broadband parity).""" + set_device_property("DCM_SCHEDULED_LOG_COLLECT", "false") + create_test_log_files(count=3) + + args = "'' 0 0 0 HTTP http://localhost:8080 0 0 ''" + result = run_uploadstblogs(args) + + # The collection step must NOT run when the flag is false/absent + collect_logs = grep_uploadstb_logs_regex( + r"Collecting current logs|Scheduled DCM log collection enabled") + assert len(collect_logs) == 0, \ + "DCM_SCHEDULED_LOG_COLLECT=false must not stage current logs" + assert result.returncode in [0, 1], "DCM upload should complete" + class TestRBUSIntegration: """Test suite for RBUS event triggered uploads""" @@ -220,9 +252,9 @@ def setup_and_teardown(self): def test_rbus_parameter_loading(self): """Test: Service loads parameters from RBUS/TR-181""" create_test_log_files(count=1) - + result = run_uploadstblogs() - + # Check for RBUS initialization rbus_logs = grep_uploadstb_logs_regex(r"rbus|RBUS|TR-181|Device\.DeviceInfo") # RBUS parameters may be loaded during context init @@ -235,22 +267,22 @@ def test_rbus_triggered_upload_via_cli(self): rbus_check = sp.run("which rbuscli", shell=True, capture_output=True) if rbus_check.returncode != 0: pytest.skip("rbuscli not available") - + create_test_log_files(count=1) - + # Trigger via RBUS would be done through DCM agent typically # For direct test, we use command line args result = run_uploadstblogs() - + assert result.returncode in [0, 1], "RBUS-triggered upload should work" @pytest.mark.order(3) def test_rbus_configuration_loading(self): """Test: Service loads upload configuration from RBUS""" create_test_log_files(count=1) - + result = run_uploadstblogs() - + # Check for configuration loading config_logs = grep_uploadstb_logs_regex(r"load.*TR-181|load.*param|endpoint|RFC") # Should attempt to load config @@ -260,9 +292,9 @@ def test_rbus_configuration_loading(self): def test_rbus_event_publishing(self): """Test: Upload success event is published via RBUS""" create_test_log_files(count=1) - + result = run_uploadstblogs() - + # Check for event publishing event_logs = grep_uploadstb_logs_regex(r"event|publish|success") # Should complete @@ -287,12 +319,12 @@ def setup_and_teardown(self): def test_strategy_selection_based_on_flags(self): """Test: Correct strategy is selected based on flags""" create_test_log_files(count=1) - + # Test different flag combinations # RRD mode: RRD_FLAG=1 args = "'' 0 0 0 HTTP http://localhost:8080 0 1 /opt/logs/rrd.log" result = run_uploadstblogs(args) - + # Check for strategy selection strategy_logs = grep_uploadstb_logs_regex(r"strategy|RRD|select") assert result.returncode in [0, 1], "Should select appropriate strategy" @@ -301,11 +333,11 @@ def test_strategy_selection_based_on_flags(self): def test_multiple_strategy_parameters(self): """Test: Service handles multiple strategy parameters""" create_test_log_files(count=1) - + # Test with various parameters args = "'' 1 1 1 HTTPS https://localhost:8443 1 0 ''" result = run_uploadstblogs(args) - + # Should handle all parameters assert result.returncode in [0, 1], "Should handle multiple parameters" @@ -313,10 +345,10 @@ def test_multiple_strategy_parameters(self): def test_strategy_logging(self): """Test: Selected strategy is logged""" create_test_log_files(count=1) - + args = "'' 0 0 1 HTTP http://localhost:8080 2 0 ''" result = run_uploadstblogs(args) - + # Check strategy logging logs = grep_uploadstb_logs_regex(r"strategy|STRAT_|upload.*type") # Strategy should be determined diff --git a/uploadstblogs/docs/hld/uploadSTBLogs_HLD.md b/uploadstblogs/docs/hld/uploadSTBLogs_HLD.md index 2b76fab2..ad96edc6 100755 --- a/uploadstblogs/docs/hld/uploadSTBLogs_HLD.md +++ b/uploadstblogs/docs/hld/uploadSTBLogs_HLD.md @@ -246,4 +246,10 @@ int main(int argc, char** argv) { ## 18. Non-Extended Design Choices Excluded any unrelated enhancements (alternate compression, multi-protocol expansion, scheduler integration) to preserve diagram fidelity. +## 19. RDK-C Additions (Camera) + +One RDK-C-specific behavior extends the base design on camera (sysvinit) platforms; it is inert on STB/broadband: + +- **Scheduled log collection** — gated by the `DCM_SCHEDULED_LOG_COLLECT` device property. When enabled, the DCM strategy's `dcm_setup` stages the current `/opt/logs` tree into `DCM_LOG_PATH` (via `copy_files_to_dcm_path`) before archiving, so the scheduled upload carries current logs. Default off ⇒ STB/broadband batch-drain behavior is unchanged. + ``` diff --git a/uploadstblogs/docs/requirements/uploadSTBLogs_requirements.md b/uploadstblogs/docs/requirements/uploadSTBLogs_requirements.md index 3834b22b..94e2ee2a 100755 --- a/uploadstblogs/docs/requirements/uploadSTBLogs_requirements.md +++ b/uploadstblogs/docs/requirements/uploadSTBLogs_requirements.md @@ -11,6 +11,7 @@ The C migration must replicate the shell script’s logic for conditional log pa - Verification → cleanup + notification (events + telemetry). - Security layer (cert handling, TLS/MTLS, optional OCSP validation). - Support modules: configuration, log collection, file ops, event emission. +- **RDK-C:** optional scheduled log collection (`DCM_SCHEDULED_LOG_COLLECT` device property) staging current `/opt/logs` into `DCM_LOG_PATH` before the scheduled DCM upload; default off (STB/broadband unchanged). ## 2. Inputs @@ -94,7 +95,7 @@ The C migration must replicate the shell script’s logic for conditional log pa - Log each stage (strategy chosen, path selected, attempt counts, HTTP codes). - Log SHA256 hash of the archive at INFO level before each Direct upload for traceability. - Telemetry counters keyed to success, failure, fallback, curl and cert errors. - + ## 10. Migration Non-Functional Requirements | Requirement | Description | diff --git a/uploadstblogs/include/uploadlogsnow.h b/uploadstblogs/include/uploadlogsnow.h index 7dbad90f..b9f1309a 100644 --- a/uploadstblogs/include/uploadlogsnow.h +++ b/uploadstblogs/include/uploadlogsnow.h @@ -33,7 +33,7 @@ extern "C" { /** * @brief Execute UploadLogsNow workflow - * + * * This function replicates the behavior of the original UploadLogsNow.sh script: * 1. Creates DCM_LOG_PATH directory * 2. Copies all files from LOG_PATH to DCM_LOG_PATH (excluding certain directories) @@ -41,12 +41,27 @@ extern "C" { * 4. Creates tar archive * 5. Uploads using ONDEMAND strategy * 6. Cleans up temporary files - * + * * @param ctx Runtime context with configuration and paths * @return 0 on success, negative value on failure */ int execute_uploadlogsnow_workflow(RuntimeContext* ctx); +/** + * @brief Copy top-level files from a source directory into DCM_LOG_PATH + * + * Copies each regular file from @p src_path into @p dest_path, excluding the + * `dcm/`, `PreviousLogs/`, and `PreviousLogs_backup/` sub-directories (so it never + * recurses into its own staging/backup dirs). Used by the on-demand UploadLogsNow + * workflow and by the scheduled DCM strategy on platforms that opt into current-log + * collection (RDK-C, DCM_SCHEDULED_LOG_COLLECT). + * + * @param src_path Source directory (e.g. LOG_PATH) + * @param dest_path Destination directory (DCM_LOG_PATH) + * @return Number of files copied (>= 0), or -1 on source open failure + */ +int copy_files_to_dcm_path(const char* src_path, const char* dest_path); + #ifdef __cplusplus } #endif diff --git a/uploadstblogs/include/uploadstblogs_types.h b/uploadstblogs/include/uploadstblogs_types.h index d2ef38fd..f7918f54 100755 --- a/uploadstblogs/include/uploadstblogs_types.h +++ b/uploadstblogs/include/uploadstblogs_types.h @@ -279,7 +279,7 @@ typedef struct { /** * @struct RuntimeContext * @brief Complete runtime context with all configuration fields flattened - * + * * Design: Completely flat structure - all fields are direct members. * Access pattern: ctx->field_name (e.g., ctx->rrd_flag, ctx->log_path) */ @@ -290,7 +290,7 @@ typedef struct { int flag; /**< General upload flag */ int upload_on_reboot; /**< Upload on reboot flag */ int trigger_type; /**< Type of upload trigger */ - + // Upload behavior settings bool privacy_do_not_share; /**< Privacy mode enabled */ bool ocsp_enabled; /**< OCSP validation enabled */ @@ -303,7 +303,8 @@ typedef struct { bool maintenance_enabled; /**< Maintenance mode enabled */ bool uploadlogsnow_mode; /**< UploadLogsNow mode enabled */ time_t archive_ref_time; /**< Reference time for archive filename (0 = use system time) */ - + bool collect_scheduled_logs; /**< RDK-C: stage current logs into DCM_LOG_PATH before the scheduled DCM upload (DCM_SCHEDULED_LOG_COLLECT) */ + // File system paths char log_path[MAX_PATH_LENGTH]; /**< Main log directory */ char prev_log_path[MAX_PATH_LENGTH]; /**< Previous logs directory */ @@ -315,23 +316,23 @@ typedef struct { char dcm_log_file[MAX_PATH_LENGTH]; /**< DCM log file path */ char dcm_log_path[MAX_PATH_LENGTH]; /**< DCM log directory */ char iarm_event_binary[MAX_PATH_LENGTH]; /**< IARM event sender location */ - + // Upload endpoints char endpoint_url[MAX_URL_LENGTH]; /**< Upload endpoint URL */ char upload_http_link[MAX_URL_LENGTH]; /**< HTTP upload link */ char presign_url[MAX_URL_LENGTH]; /**< Pre-signed URL */ char proxy_bucket[MAX_URL_LENGTH]; /**< Proxy bucket for fallback uploads */ - + // Device information char mac_address[MAX_MAC_LENGTH]; /**< Device MAC address */ char device_type[32]; /**< Device type (mediaclient, etc.) */ char build_type[32]; /**< Build type */ - + // Certificate paths char cert_path[MAX_CERT_PATH_LENGTH]; /**< Client certificate path */ char key_path[MAX_CERT_PATH_LENGTH]; /**< Private key path */ char ca_cert_path[MAX_CERT_PATH_LENGTH]; /**< CA certificate path */ - + // Retry configuration int direct_max_attempts; /**< Max attempts for direct path */ int codebig_max_attempts; /**< Max attempts for CodeBig path */ diff --git a/uploadstblogs/src/context_manager.c b/uploadstblogs/src/context_manager.c index a713ed2e..32fed321 100755 --- a/uploadstblogs/src/context_manager.c +++ b/uploadstblogs/src/context_manager.c @@ -51,7 +51,7 @@ bool is_direct_blocked(int block_time) { const char *block_file = "/tmp/.lastdirectfail_upl"; struct stat file_stat; - + // Open file with O_NOFOLLOW to prevent symlink attacks, O_RDONLY for reading metadata int fd = open(block_file, O_RDONLY | O_NOFOLLOW); if (fd < 0) { @@ -63,29 +63,29 @@ bool is_direct_blocked(int block_time) } return false; } - + // Use fstat on the open file descriptor to avoid TOCTOU race if (fstat(fd, &file_stat) != 0) { close(fd); return false; } - + close(fd); - + time_t current_time = time(NULL); time_t mod_time = file_stat.st_mtime; time_t elapsed = current_time - mod_time; - + if (elapsed <= block_time) { // Still within block period int remaining_hours = (block_time - elapsed) / 3600; - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Last direct failed blocking is still valid for %d hrs, preventing direct\n", __FUNCTION__, __LINE__, remaining_hours); return true; } else { // Block period expired, remove file (ignore errors if file disappeared) - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Last direct failed blocking has expired, removing %s, allowing direct\n", __FUNCTION__, __LINE__, block_file); if (unlink(block_file) != 0 && errno != ENOENT) { @@ -106,7 +106,7 @@ bool is_codebig_blocked(int block_time) { const char *block_file = "/tmp/.lastcodebigfail_upl"; struct stat file_stat; - + // Open file with O_NOFOLLOW to prevent symlink attacks, O_RDONLY for reading metadata int fd = open(block_file, O_RDONLY | O_NOFOLLOW); if (fd < 0) { @@ -118,29 +118,29 @@ bool is_codebig_blocked(int block_time) } return false; } - + // Use fstat on the open file descriptor to avoid TOCTOU race if (fstat(fd, &file_stat) != 0) { close(fd); return false; } - + close(fd); - + time_t current_time = time(NULL); time_t mod_time = file_stat.st_mtime; time_t elapsed = current_time - mod_time; - + if (elapsed <= block_time) { // Still within block period int remaining_mins = (block_time - elapsed) / 60; - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Last Codebig failed blocking is still valid for %d mins, preventing Codebig\n", __FUNCTION__, __LINE__, remaining_mins); return true; } else { // Block period expired, remove file (ignore errors if file disappeared) - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Last Codebig failed blocking has expired, removing %s, allowing Codebig\n", __FUNCTION__, __LINE__, block_file); if (unlink(block_file) != 0 && errno != ENOENT) { @@ -155,6 +155,7 @@ bool is_codebig_blocked(int block_time) bool init_context(RuntimeContext* ctx) { // Initialize RDK Logger +#ifdef RDK_LOGGER_EXT /* Extended initialization with programmatic configuration */ rdk_logger_ext_config_t config = { .pModuleName = "LOG.RDK.UPLOADSTB", /* Module name */ @@ -163,10 +164,20 @@ bool init_context(RuntimeContext* ctx) .format = RDKLOG_FORMAT_WITH_TS, /* Timestamped format */ .pFilePolicy = NULL /* Not using file output, so NULL */ }; - + if (rdk_logger_ext_init(&config) != RDK_SUCCESS) { printf("UPLOADSTB : ERROR - Extended logger init failed\n"); } +#else + /* Platforms with an older rdk-logger (e.g. RDKC's 2.4.0) do not provide the + * extended programmatic-config API: rdk_logger_ext_config_t there is a + * file-rotation struct and RDKLOG_OUTPUT_CONSOLE/RDKLOG_FORMAT_WITH_TS are + * absent. Fall back to the standard debug.ini init, matching the guard + * already used in backup_logs.c and usb_log_utils.c. */ + if (rdk_logger_init(DEBUG_INI_NAME) != RDK_SUCCESS) { + printf("UPLOADSTB : ERROR - Logger init failed\n"); + } +#endif if (!ctx) { RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Context pointer is NULL\n", __FUNCTION__, __LINE__); return false; @@ -196,10 +207,10 @@ bool init_context(RuntimeContext* ctx) // Final context validation summary RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Context initialization successful\n", __FUNCTION__, __LINE__); RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Device MAC: '%s', Type: '%s'\n", - __FUNCTION__, __LINE__, + __FUNCTION__, __LINE__, ctx->mac_address, strlen(ctx->device_type) > 0 ? ctx->device_type : "(empty)"); - + return true; } @@ -237,14 +248,14 @@ bool load_environment(RuntimeContext* ctx) strcpy(ctx->prev_log_path, ctx->log_path); strcat(ctx->prev_log_path, "/PreviousLogs"); } else { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] LOG_PATH too long for constructing PREV_LOG_PATH\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] LOG_PATH too long for constructing PREV_LOG_PATH\n", __FUNCTION__, __LINE__); strncpy(ctx->prev_log_path, "/opt/logs/PreviousLogs", sizeof(ctx->prev_log_path) - 1); ctx->prev_log_path[sizeof(ctx->prev_log_path) - 1] = '\0'; } // Set DRI_LOG_PATH (hardcoded in script) - strncpy(ctx->dri_log_path, "/opt/logs/drilogs", + strncpy(ctx->dri_log_path, "/opt/logs/drilogs", sizeof(ctx->dri_log_path) - 1); ctx->dri_log_path[sizeof(ctx->dri_log_path) - 1] = '\0'; @@ -255,7 +266,7 @@ bool load_environment(RuntimeContext* ctx) strcpy(ctx->rrd_file, ctx->log_path); strcat(ctx->rrd_file, "/remote-debugger.log"); } else { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] LOG_PATH too long for constructing RRD_LOG_FILE\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] LOG_PATH too long for constructing RRD_LOG_FILE\n", __FUNCTION__, __LINE__); strncpy(ctx->rrd_file, "/opt/logs/remote-debugger.log", sizeof(ctx->rrd_file) - 1); ctx->rrd_file[sizeof(ctx->rrd_file) - 1] = '\0'; @@ -328,7 +339,7 @@ bool load_environment(RuntimeContext* ctx) strcpy(ctx->dcm_log_file, ctx->log_path); strcat(ctx->dcm_log_file, "/dcmscript.log"); } else { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] LOG_PATH too long for constructing DCM_LOG_FILE\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] LOG_PATH too long for constructing DCM_LOG_FILE\n", __FUNCTION__, __LINE__); strncpy(ctx->dcm_log_file, "/opt/logs/dcmscript.log", sizeof(ctx->dcm_log_file) - 1); ctx->dcm_log_file[sizeof(ctx->dcm_log_file) - 1] = '\0'; @@ -348,10 +359,10 @@ bool load_environment(RuntimeContext* ctx) // Create DCM log directory if it doesn't exist (matches script behavior) if (!dir_exists(ctx->dcm_log_path)) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM log folder does not exist. Creating now: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM log folder does not exist. Creating now: %s\n", __FUNCTION__, __LINE__, ctx->dcm_log_path); if (!create_directory(ctx->dcm_log_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to create DCM log directory: %s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to create DCM log directory: %s\n", __FUNCTION__, __LINE__, ctx->dcm_log_path); // Continue anyway - not a fatal error } @@ -360,7 +371,7 @@ bool load_environment(RuntimeContext* ctx) // Check for TLS support (set TLS flag if /etc/os-release exists) struct stat st_osrelease; bool os_release_exists = (stat("/etc/os-release", &st_osrelease) == 0); - + if (os_release_exists) { ctx->tls_enabled = true; RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] TLS 1.2 support enabled\n", __FUNCTION__, __LINE__); @@ -375,7 +386,7 @@ bool load_environment(RuntimeContext* ctx) strncpy(ctx->iarm_event_binary, "/usr/local/bin", sizeof(ctx->iarm_event_binary) - 1); } ctx->iarm_event_binary[sizeof(ctx->iarm_event_binary) - 1] = '\0'; - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] IARM_EVENT_BINARY_LOCATION=%s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] IARM_EVENT_BINARY_LOCATION=%s\n", __FUNCTION__, __LINE__, ctx->iarm_event_binary); // Check for maintenance mode enable @@ -397,12 +408,25 @@ bool load_environment(RuntimeContext* ctx) ctx->include_dri = true; RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DRI log collection enabled\n", __FUNCTION__, __LINE__); - + // RDK-C: stage current logs into DCM_LOG_PATH before the scheduled DCM upload. + // On STB/broadband DCM_LOG_PATH is batched externally (Maintenance Manager / + // on-demand), so this stays OFF and the DCM strategy remains a pure batch-drain. + // The RDK-C camera has no external batcher, so it opts in via device.properties + // (DCM_SCHEDULED_LOG_COLLECT=true) to restore the legacy copyOptLogsFiles step. + memset(buffer, 0, sizeof(buffer)); + if (getDevicePropertyData("DCM_SCHEDULED_LOG_COLLECT", buffer, sizeof(buffer)) == UTILS_SUCCESS) { + if (strcasecmp(buffer, "true") == 0) { + ctx->collect_scheduled_logs = true; + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Scheduled DCM log collection enabled\n", __FUNCTION__, __LINE__); + } + } + + // Check for OCSP marker files // EnableOCSPStapling="/tmp/.EnableOCSPStapling" // EnableOCSP="/tmp/.EnableOCSPCA" struct stat st_ocsp; - if (stat("/tmp/.EnableOCSPStapling", &st_ocsp) == 0 || + if (stat("/tmp/.EnableOCSPStapling", &st_ocsp) == 0 || stat("/tmp/.EnableOCSPCA", &st_ocsp) == 0) { ctx->ocsp_enabled = true; RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] OCSP validation enabled\n", __FUNCTION__, __LINE__); @@ -441,9 +465,9 @@ bool load_tr181_params(RuntimeContext* ctx) // Load LogUploadEndpoint URL // Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.LogUploadEndpoint.URL if (!rbus_get_string_param("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.LogUploadEndpoint.URL", - ctx->endpoint_url, + ctx->endpoint_url, sizeof(ctx->endpoint_url))) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to get LogUploadEndpoint.URL\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to get LogUploadEndpoint.URL\n", __FUNCTION__, __LINE__); } @@ -451,7 +475,7 @@ bool load_tr181_params(RuntimeContext* ctx) // Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.EncryptCloudUpload.Enable if (!rbus_get_bool_param("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.EncryptCloudUpload.Enable", &ctx->encryption_enable)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to get EncryptCloudUpload.Enable, using default: false\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to get EncryptCloudUpload.Enable, using default: false\n", __FUNCTION__, __LINE__); ctx->encryption_enable = false; } @@ -463,16 +487,16 @@ bool load_tr181_params(RuntimeContext* ctx) privacy_mode, sizeof(privacy_mode))) { // PrivacyMode values: "DO_NOT_SHARE" or "SHARE" ctx->privacy_do_not_share = (strcasecmp(privacy_mode, "DO_NOT_SHARE") == 0); - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Privacy Mode: %s (do_not_share=%d)\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Privacy Mode: %s (do_not_share=%d)\n", __FUNCTION__, __LINE__, privacy_mode, ctx->privacy_do_not_share); } else { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to get PrivacyMode, using default: false\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to get PrivacyMode, using default: false\n", __FUNCTION__, __LINE__); ctx->privacy_do_not_share = false; } RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] TR-181 parameters loaded via RBUS\n", __FUNCTION__, __LINE__); - + // Note: UploadLogsOnUnscheduledReboot.Disable is loaded at runtime when needed in maintenance window // Note: RDKRemoteDebugger.IssueType is only used for RRD mode which has separate handling @@ -489,13 +513,13 @@ bool get_mac_address(char* mac_buf, size_t buf_size) } size_t copied = GetEstbMac(mac_buf, buf_size); - + if (copied > 0 && strlen(mac_buf) > 0) { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] MAC address: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] MAC address: %s\n", __FUNCTION__, __LINE__, mac_buf); return true; } else { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to get MAC address\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to get MAC address\n", __FUNCTION__, __LINE__); return false; } diff --git a/uploadstblogs/src/strategies.c b/uploadstblogs/src/strategies.c index 60e40312..680cc843 100644 --- a/uploadstblogs/src/strategies.c +++ b/uploadstblogs/src/strategies.c @@ -20,10 +20,10 @@ /** * @file strategies.c * @brief Upload strategy implementations - * + * * Combines strategy_dcm, strategy_ondemand, and strategy_reboot functionality. * Each strategy has its own setup, archive, upload, and cleanup phases. - * + * * Strategy Summary: * - DCM: Batched uploads from DCM_LOG_PATH, entire directory deleted after upload * - ONDEMAND: Immediate upload from temp directory, original logs preserved @@ -59,6 +59,7 @@ #include "json_parse.h" #include "urlHelper.h" #include "secure_wrapper.h" +#include "uploadlogsnow.h" #define ONDEMAND_TEMP_DIR "/tmp/log_on_demand" #define DEFAULT_DL_ALLOC 1024 @@ -307,7 +308,7 @@ int wait_for_telemetry_prevlogs_done(void) /** * @brief Read upload_flag from DCMSettings.conf * @return true if upload is enabled, false otherwise - * + * * Shell script equivalent: * if [ -f "/tmp/DCMSettings.conf" ]; then * upload_flag=`cat /tmp/DCMSettings.conf | grep 'urn:settings:LogUploadSettings:upload' | cut -d '=' -f2 | sed 's/^"//' | sed 's/"$//'` @@ -317,17 +318,17 @@ static bool read_dcm_upload_flag(void) { const char* dcm_settings_file = "/tmp/DCMSettings.conf"; FILE* fp = fopen(dcm_settings_file, "r"); - + if (!fp) { RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] DCMSettings.conf not found, assuming upload enabled\n", __FUNCTION__, __LINE__); return true; // Default to enabled if file doesn't exist } - + bool upload_enabled = false; char line[512]; - + // Search for "urn:settings:LogUploadSettings:upload" line while (fgets(line, sizeof(line), fp)) { if (strstr(line, "urn:settings:LogUploadSettings:upload")) { @@ -335,17 +336,17 @@ static bool read_dcm_upload_flag(void) char* equals = strchr(line, '='); if (equals) { equals++; // Move past '=' - + // Skip whitespace and quotes while (*equals && (isspace(*equals) || *equals == '"')) { equals++; } - + // Check if value is "true" if (strncasecmp(equals, "true", 4) == 0) { upload_enabled = true; } - + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM upload_flag from DCMSettings.conf: %s\n", __FUNCTION__, __LINE__, upload_enabled ? "true" : "false"); @@ -353,7 +354,7 @@ static bool read_dcm_upload_flag(void) break; } } - + fclose(fp); return upload_enabled; } @@ -368,7 +369,7 @@ const StrategyHandler dcm_strategy_handler = { /** * @brief Setup phase for DCM strategy - * + * * Shell script equivalent (uploadDCMLogs lines 698-705): * 1. Change to DCM_LOG_PATH (files already there from batching) * 2. Check upload_flag @@ -377,44 +378,67 @@ const StrategyHandler dcm_strategy_handler = { static int dcm_setup(RuntimeContext* ctx, SessionState* session) { if (!ctx) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Invalid context parameter\n", __FUNCTION__, __LINE__); return -1; } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM: Starting setup phase\n", __FUNCTION__, __LINE__); // Check if DCM_LOG_PATH exists and has files if (!dir_exists(ctx->dcm_log_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] DCM_LOG_PATH does not exist: %s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] DCM_LOG_PATH does not exist: %s\n", __FUNCTION__, __LINE__, ctx->dcm_log_path); return -1; } // Check upload_flag from DCMSettings.conf (matches script behavior) if (!read_dcm_upload_flag()) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] DCM upload_flag is false, skipping DCM upload\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] DCM upload_flag is false, skipping DCM upload\n", __FUNCTION__, __LINE__); return -1; // Signal to skip upload } + // RDK-C: stage current logs into DCM_LOG_PATH before archiving. + // Restores the legacy uploadSTBLogs.sh copyOptLogsFiles step (copy LOG_PATH/* + // into DCM_LOG_PATH) that the C port dropped. Gated by collect_scheduled_logs + // (device.properties DCM_SCHEDULED_LOG_COLLECT) so STB/broadband stay a pure + // batch-drain. copy_files_to_dcm_path excludes dcm/PreviousLogs/PreviousLogs_backup + // (no recursion); dcm_cleanup later removes only DCM_LOG_PATH, never LOG_PATH. + if (ctx->collect_scheduled_logs) { + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Collecting current logs from %s into DCM_LOG_PATH %s\n", + __FUNCTION__, __LINE__, ctx->log_path, ctx->dcm_log_path); + int collected = copy_files_to_dcm_path(ctx->log_path, ctx->dcm_log_path); + if (collected < 0) { + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to collect current logs into DCM_LOG_PATH\n", + __FUNCTION__, __LINE__); + // Continue anyway - archive whatever is already present + } else { + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Collected %d current log file(s) into DCM_LOG_PATH\n", + __FUNCTION__, __LINE__, collected); + } + } + // Add timestamps to all files in DCM_LOG_PATH - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Adding timestamps to files in DCM_LOG_PATH\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Adding timestamps to files in DCM_LOG_PATH\n", __FUNCTION__, __LINE__); - + int ret = add_timestamp_to_files(ctx->dcm_log_path); if (ret != 0) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Failed to add timestamps to some files\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to add timestamps to some files\n", __FUNCTION__, __LINE__); // Continue anyway, not critical } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM: Setup phase complete\n", __FUNCTION__, __LINE__); return 0; @@ -422,7 +446,7 @@ static int dcm_setup(RuntimeContext* ctx, SessionState* session) /** * @brief Archive phase for DCM strategy - * + * * Shell script equivalent (uploadDCMLogs lines 706-717): * - Collect PCAP files to DCM_LOG_PATH if mediaclient * - Create tar.gz archive from all files in DCM_LOG_PATH @@ -431,22 +455,22 @@ static int dcm_setup(RuntimeContext* ctx, SessionState* session) static int dcm_archive(RuntimeContext* ctx, SessionState* session) { if (!ctx || !session) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Invalid parameters (ctx=%p, session=%p)\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Invalid parameters (ctx=%p, session=%p)\n", __FUNCTION__, __LINE__, (void*)ctx, (void*)session); return -1; } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM: Starting archive phase\n", __FUNCTION__, __LINE__); // Collect PCAP files directly to DCM_LOG_PATH if mediaclient if (ctx->include_pcap) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Collecting PCAP file to DCM_LOG_PATH\n", __FUNCTION__, __LINE__); int count = collect_pcap_logs(ctx, ctx->dcm_log_path); if (count > 0) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Collected %d PCAP file\n", __FUNCTION__, __LINE__, count); } } @@ -454,7 +478,7 @@ static int dcm_archive(RuntimeContext* ctx, SessionState* session) // Create archive from DCM_LOG_PATH (files already have timestamps) int ret = create_archive(ctx, session, ctx->dcm_log_path); if (ret != 0) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to create archive\n", __FUNCTION__, __LINE__); return -1; } @@ -462,7 +486,7 @@ static int dcm_archive(RuntimeContext* ctx, SessionState* session) #ifndef L2_TEST_ENABLED sleep(60); #endif - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM: Archive phase complete\n", __FUNCTION__, __LINE__); return 0; @@ -470,7 +494,7 @@ static int dcm_archive(RuntimeContext* ctx, SessionState* session) /** * @brief Upload phase for DCM strategy - * + * * Shell script equivalent (uploadDCMLogs lines 718-732): * - Upload archive via HTTP * - Clear old packet captures @@ -478,26 +502,26 @@ static int dcm_archive(RuntimeContext* ctx, SessionState* session) static int dcm_upload(RuntimeContext* ctx, SessionState* session) { if (!ctx || !session) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Invalid parameters (ctx=%p, session=%p)\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Invalid parameters (ctx=%p, session=%p)\n", __FUNCTION__, __LINE__, (void*)ctx, (void*)session); return -1; } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM: Starting upload phase\n", __FUNCTION__, __LINE__); // Construct full archive path using session archive filename char archive_path[MAX_PATH_LENGTH]; - if (!join_path(archive_path, sizeof(archive_path), + if (!join_path(archive_path, sizeof(archive_path), ctx->dcm_log_path, session->archive_file)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Archive path too long\n", __FUNCTION__, __LINE__); return -1; } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Uploading DCM logs: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Uploading DCM logs: %s\n", __FUNCTION__, __LINE__, archive_path); // Upload the archive (session->success is set by execute_upload_cycle) @@ -505,12 +529,12 @@ static int dcm_upload(RuntimeContext* ctx, SessionState* session) // Clear old packet captures if (ctx->include_pcap) { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] Clearing old packet captures\n", __FUNCTION__, __LINE__); clear_old_packet_captures(ctx->log_path); } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] DCM: Upload phase complete\n", __FUNCTION__, __LINE__); return ret; @@ -518,7 +542,7 @@ static int dcm_upload(RuntimeContext* ctx, SessionState* session) /** * @brief Cleanup phase for DCM strategy - * + * * Shell script equivalent (uploadDCMLogs lines 735-737): * - Delete entire DCM_LOG_PATH directory * - No permanent backup created @@ -527,31 +551,31 @@ static int dcm_upload(RuntimeContext* ctx, SessionState* session) static int dcm_cleanup(RuntimeContext* ctx, SessionState* session, bool upload_success) { if (!ctx) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Invalid context parameter\n", __FUNCTION__, __LINE__); return -1; } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] DCM: Starting cleanup phase (upload_success=%d)\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] DCM: Starting cleanup phase (upload_success=%d)\n", __FUNCTION__, __LINE__, upload_success); // Delete entire DCM_LOG_PATH directory if (dir_exists(ctx->dcm_log_path)) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Removing DCM_LOG_PATH: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Removing DCM_LOG_PATH: %s\n", __FUNCTION__, __LINE__, ctx->dcm_log_path); - + if (!remove_directory(ctx->dcm_log_path)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Failed to remove DCM_LOG_PATH\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to remove DCM_LOG_PATH\n", __FUNCTION__, __LINE__); return -1; } } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] DCM: Cleanup phase complete. DCM_LOG_PATH removed.\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] DCM: Cleanup phase complete. DCM_LOG_PATH removed.\n", __FUNCTION__, __LINE__); return 0; @@ -580,7 +604,7 @@ const StrategyHandler ondemand_strategy_handler = { /** * @brief Setup phase for ONDEMAND strategy - * + * * Shell script equivalent (uploadLogOnDemand lines 747-763): * 1. Check if logs exist in LOG_PATH * 2. Create /tmp/log_on_demand @@ -591,9 +615,9 @@ const StrategyHandler ondemand_strategy_handler = { */ static int ondemand_setup(RuntimeContext* ctx, SessionState* session) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] ONDEMAND: Starting setup phase\n", __FUNCTION__, __LINE__); - + // Verify context RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] Context in setup: ctx=%p, MAC='%s', device_type='%s'\n", @@ -606,13 +630,13 @@ static int ondemand_setup(RuntimeContext* ctx, SessionState* session) // ret=`ls $LOG_PATH/*.txt` // if [ ! $ret ]; then ret=`ls $LOG_PATH/*.log` if (!dir_exists(ctx->log_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] LOG_PATH does not exist: %s\n", __FUNCTION__, __LINE__, ctx->log_path); return -1; } if (!has_log_files(ctx->log_path)) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] No .txt or .log files in LOG_PATH, aborting\n", __FUNCTION__, __LINE__); emit_no_logs_ondemand(); return -1; @@ -620,32 +644,32 @@ static int ondemand_setup(RuntimeContext* ctx, SessionState* session) // Create temp directory: /tmp/log_on_demand if (dir_exists(ONDEMAND_TEMP_DIR)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Temp directory already exists, cleaning: %s\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Temp directory already exists, cleaning: %s\n", __FUNCTION__, __LINE__, ONDEMAND_TEMP_DIR); remove_directory(ONDEMAND_TEMP_DIR); } if (!create_directory(ONDEMAND_TEMP_DIR)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Failed to create temp directory: %s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Failed to create temp directory: %s\n", __FUNCTION__, __LINE__, ONDEMAND_TEMP_DIR); return -1; } // Copy log files from LOG_PATH to temp directory - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Copying logs from %s to %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Copying logs from %s to %s\n", __FUNCTION__, __LINE__, ctx->log_path, ONDEMAND_TEMP_DIR); int count = collect_logs(ctx, session, ONDEMAND_TEMP_DIR); if (count <= 0) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] No log files collected\n", __FUNCTION__, __LINE__); return -1; } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Collected %d log files\n", __FUNCTION__, __LINE__, count); // Create timestamp for permanent log path (for logging purposes only) @@ -668,20 +692,20 @@ static int ondemand_setup(RuntimeContext* ctx, SessionState* session) char perm_log_path[MAX_PATH_LENGTH]; int written = snprintf(perm_log_path, sizeof(perm_log_path), "%s/%s", ctx->log_path, timestamp); - + if (written >= (int)sizeof(perm_log_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Permanent log path too long\n", __FUNCTION__, __LINE__); return -1; } // Log to lastlog_path file char lastlog_path_file[MAX_PATH_LENGTH]; - written = snprintf(lastlog_path_file, sizeof(lastlog_path_file), "%s/lastlog_path", + written = snprintf(lastlog_path_file, sizeof(lastlog_path_file), "%s/lastlog_path", ctx->telemetry_path); - + if (written >= (int)sizeof(lastlog_path_file)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Lastlog path file too long\n", __FUNCTION__, __LINE__); return -1; } @@ -690,24 +714,24 @@ static int ondemand_setup(RuntimeContext* ctx, SessionState* session) if (fp) { fprintf(fp, "%s\n", perm_log_path); fclose(fp); - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, - "[%s:%d] Logged to lastlog_path: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + "[%s:%d] Logged to lastlog_path: %s\n", __FUNCTION__, __LINE__, perm_log_path); } // Delete old tar file if exists char old_tar[MAX_PATH_LENGTH]; - snprintf(old_tar, sizeof(old_tar), "%s/%s", + snprintf(old_tar, sizeof(old_tar), "%s/%s", ONDEMAND_TEMP_DIR, session->archive_file); - + if (file_exists(old_tar)) { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, - "[%s:%d] Removing old tar file: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + "[%s:%d] Removing old tar file: %s\n", __FUNCTION__, __LINE__, old_tar); remove_file(old_tar); } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] ONDEMAND: Setup phase complete\n", __FUNCTION__, __LINE__); return 0; @@ -715,7 +739,7 @@ static int ondemand_setup(RuntimeContext* ctx, SessionState* session) /** * @brief Archive phase for ONDEMAND strategy - * + * * Shell script equivalent (uploadLogOnDemand lines 769-771): * - NO timestamp modification (files keep original names) * - Create tar.gz from all files in temp directory @@ -723,32 +747,32 @@ static int ondemand_setup(RuntimeContext* ctx, SessionState* session) */ static int ondemand_archive(RuntimeContext* ctx, SessionState* session) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] ONDEMAND: Starting archive phase\n", __FUNCTION__, __LINE__); // Debug: verify context is valid RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] Context before create_archive: ctx=%p, MAC='%s', device_type='%s'\n", - __FUNCTION__, __LINE__, + __FUNCTION__, __LINE__, (void*)ctx, (ctx && ctx->mac_address[0] != '\0') ? ctx->mac_address : "(NULL/INVALID)", (ctx && ctx->device_type[0] != '\0') ? ctx->device_type : "(empty/NULL)"); // Create archive from temp directory (NO timestamp modification) int ret = create_archive(ctx, session, ONDEMAND_TEMP_DIR); - + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] After create_archive: ret=%d, session->archive_file='%s'\n", __FUNCTION__, __LINE__, ret, session ? session->archive_file : "(NULL SESSION)"); if (ret != 0) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to create archive\n", __FUNCTION__, __LINE__); return -1; } sleep(2); - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] ONDEMAND: Archive phase complete\n", __FUNCTION__, __LINE__); return 0; @@ -756,20 +780,20 @@ static int ondemand_archive(RuntimeContext* ctx, SessionState* session) /** * @brief Upload phase for ONDEMAND strategy - * + * * Shell script equivalent (uploadLogOnDemand lines 772-784): * - Upload via HTTP if uploadLog is true * - Handle upload result and set maintenance_error_flag */ static int ondemand_upload(RuntimeContext* ctx, SessionState* session) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] ONDEMAND: Starting upload phase\n", __FUNCTION__, __LINE__); // Check if upload is enabled if (!ctx->flag) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Upload flag is false, skipping upload\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Upload flag is false, skipping upload\n", __FUNCTION__, __LINE__); return 0; } @@ -778,20 +802,20 @@ static int ondemand_upload(RuntimeContext* ctx, SessionState* session) RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] session->archive_file='%s'\n", __FUNCTION__, __LINE__, session->archive_file); - + char archive_path[MAX_PATH_LENGTH]; - snprintf(archive_path, sizeof(archive_path), "%s/%s", + snprintf(archive_path, sizeof(archive_path), "%s/%s", ONDEMAND_TEMP_DIR, session->archive_file); - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Uploading archive: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Uploading archive: %s\n", __FUNCTION__, __LINE__, archive_path); // Upload the archive (session->success is set by execute_upload_cycle) int ret = upload_archive(ctx, session, archive_path); - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] ONDEMAND: Upload phase complete (result=%d)\n", + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] ONDEMAND: Upload phase complete (result=%d)\n", __FUNCTION__, __LINE__, ret); return ret; @@ -799,7 +823,7 @@ static int ondemand_upload(RuntimeContext* ctx, SessionState* session) /** * @brief Cleanup phase for ONDEMAND strategy - * + * * Shell script equivalent (uploadLogOnDemand lines 789-795): * - Delete tar file from temp directory * - Delete entire temp directory @@ -807,38 +831,38 @@ static int ondemand_upload(RuntimeContext* ctx, SessionState* session) */ static int ondemand_cleanup(RuntimeContext* ctx, SessionState* session, bool upload_success) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] ONDEMAND: Starting cleanup phase (upload_success=%d)\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] ONDEMAND: Starting cleanup phase (upload_success=%d)\n", __FUNCTION__, __LINE__, upload_success); // Delete tar file char tar_path[MAX_PATH_LENGTH]; - snprintf(tar_path, sizeof(tar_path), "%s/%s", + snprintf(tar_path, sizeof(tar_path), "%s/%s", ONDEMAND_TEMP_DIR, session->archive_file); if (file_exists(tar_path)) { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, - "[%s:%d] Removing tar file: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + "[%s:%d] Removing tar file: %s\n", __FUNCTION__, __LINE__, tar_path); remove_file(tar_path); } // Delete entire temp directory if (dir_exists(ONDEMAND_TEMP_DIR)) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Removing temp directory: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Removing temp directory: %s\n", __FUNCTION__, __LINE__, ONDEMAND_TEMP_DIR); - + if (!remove_directory(ONDEMAND_TEMP_DIR)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Failed to remove temp directory\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to remove temp directory\n", __FUNCTION__, __LINE__); return -1; } } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] ONDEMAND: Cleanup phase complete. Original logs preserved in %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] ONDEMAND: Cleanup phase complete. Original logs preserved in %s\n", __FUNCTION__, __LINE__, ctx->log_path); return 0; @@ -870,7 +894,7 @@ const StrategyHandler reboot_strategy_handler = { /** * @brief Setup phase for REBOOT/NON_DCM strategy - * + * * Shell script equivalent (uploadLogOnReboot lines 820-848): * 1. Check system uptime, sleep 330s if < 900s * 2. Delete old backups (3+ days old) @@ -881,7 +905,7 @@ const StrategyHandler reboot_strategy_handler = { */ static int reboot_setup(RuntimeContext* ctx, SessionState* session) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] REBOOT/NON_DCM: Starting setup phase\n", __FUNCTION__, __LINE__); /* backup_logs gate (REQ-SYNC-001). @@ -959,14 +983,14 @@ static int reboot_setup(RuntimeContext* ctx, SessionState* session) // ret=`ls $PREV_LOG_PATH/*.txt` // if [ ! $ret ]; then ret=`ls $PREV_LOG_PATH/*.log` if (!dir_exists(ctx->prev_log_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] PREV_LOG_PATH does not exist: %s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] PREV_LOG_PATH does not exist: %s\n", __FUNCTION__, __LINE__, ctx->prev_log_path); return -1; } if (!has_log_files(ctx->prev_log_path)) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] No .txt or .log files in PREV_LOG_PATH, aborting\n", __FUNCTION__, __LINE__); emit_no_logs_reboot(ctx); return -1; @@ -979,7 +1003,7 @@ static int reboot_setup(RuntimeContext* ctx, SessionState* session) } else { RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] No old log backup directories removed\n", __FUNCTION__, __LINE__); } - + // Create timestamp for permanent log path char timestamp[64]; time_t now = (ctx->archive_ref_time > 0) ? ctx->archive_ref_time : time(NULL); @@ -996,11 +1020,11 @@ static int reboot_setup(RuntimeContext* ctx, SessionState* session) } char perm_log_path[MAX_PATH_LENGTH]; - int written = snprintf(perm_log_path, sizeof(perm_log_path), "%s/%s", + int written = snprintf(perm_log_path, sizeof(perm_log_path), "%s/%s", ctx->log_path, timestamp); - + if (written >= (int)sizeof(perm_log_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Permanent log path too long\n", __FUNCTION__, __LINE__); return -1; } @@ -1011,11 +1035,11 @@ static int reboot_setup(RuntimeContext* ctx, SessionState* session) // Log to lastlog_path char lastlog_path_file[MAX_PATH_LENGTH]; - written = snprintf(lastlog_path_file, sizeof(lastlog_path_file), "%s/lastlog_path", + written = snprintf(lastlog_path_file, sizeof(lastlog_path_file), "%s/lastlog_path", ctx->telemetry_path); - + if (written >= (int)sizeof(lastlog_path_file)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Lastlog path file too long\n", __FUNCTION__, __LINE__); return -1; } @@ -1024,24 +1048,24 @@ static int reboot_setup(RuntimeContext* ctx, SessionState* session) if (fp) { fprintf(fp, "%s\n", perm_log_path); fclose(fp); - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, - "[%s:%d] Logged to lastlog_path: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + "[%s:%d] Logged to lastlog_path: %s\n", __FUNCTION__, __LINE__, perm_log_path); } // Delete old tar file if exists char old_tar[MAX_PATH_LENGTH]; written = snprintf(old_tar, sizeof(old_tar), "%s/logs.tar.gz", ctx->prev_log_path); - + if (written >= (int)sizeof(old_tar)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Old tar path too long\n", __FUNCTION__, __LINE__); return -1; } - + if (file_exists(old_tar)) { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, - "[%s:%d] Removing old tar file: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + "[%s:%d] Removing old tar file: %s\n", __FUNCTION__, __LINE__, old_tar); remove_file(old_tar); } @@ -1074,19 +1098,19 @@ static int reboot_setup(RuntimeContext* ctx, SessionState* session) } // Add timestamps to all files in PREV_LOG_PATH - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Adding timestamps to files in PREV_LOG_PATH\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Adding timestamps to files in PREV_LOG_PATH\n", __FUNCTION__, __LINE__); - + int ret = add_timestamp_to_files(ctx->prev_log_path); if (ret != 0) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Failed to add timestamps to some files\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to add timestamps to some files\n", __FUNCTION__, __LINE__); // Continue anyway, not critical } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] REBOOT/NON_DCM: Setup phase complete\n", __FUNCTION__, __LINE__); return 0; @@ -1094,7 +1118,7 @@ static int reboot_setup(RuntimeContext* ctx, SessionState* session) /** * @brief Archive phase for REBOOT/NON_DCM strategy - * + * * Shell script equivalent (uploadLogOnReboot lines 853-869): * - Collect PCAP files to PREV_LOG_PATH if mediaclient * - Create tar.gz archive from PREV_LOG_PATH @@ -1102,36 +1126,36 @@ static int reboot_setup(RuntimeContext* ctx, SessionState* session) */ static int reboot_archive(RuntimeContext* ctx, SessionState* session) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] REBOOT/NON_DCM: Starting archive phase\n", __FUNCTION__, __LINE__); // Collect PCAP files directly to PREV_LOG_PATH if mediaclient if (ctx->include_pcap) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Collecting PCAP file to PREV_LOG_PATH\n", __FUNCTION__, __LINE__); int count = collect_pcap_logs(ctx, ctx->prev_log_path); if (count > 0) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Collected %d PCAP file\n", __FUNCTION__, __LINE__, count); } } - + // Create archive from PREV_LOG_PATH (files already have timestamps) int ret = create_archive(ctx, session, ctx->prev_log_path); if (ret != 0) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to create archive\n", __FUNCTION__, __LINE__); return -1; } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] REBOOT/NON_DCM: Archive phase complete\n", __FUNCTION__, __LINE__); return 0; } /** * @brief Upload phase for REBOOT/NON_DCM strategy - * + * * Shell script equivalent (uploadLogOnReboot lines 853-890): * - Check reboot reason and RFC settings * - Upload main logs if allowed @@ -1140,7 +1164,7 @@ static int reboot_archive(RuntimeContext* ctx, SessionState* session) */ static int reboot_upload(RuntimeContext* ctx, SessionState* session) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] REBOOT/NON_DCM: Starting upload phase\n", __FUNCTION__, __LINE__); RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] UploadOnReboot set to %s\n", __FUNCTION__, __LINE__, ctx->upload_on_reboot ? "true" : "false"); @@ -1150,12 +1174,12 @@ static int reboot_upload(RuntimeContext* ctx, SessionState* session) // When DCM_FLAG=1 (DCM mode), upload_on_reboot determines the behavior bool should_upload = false; const char* reboot_info_path = "/opt/secure/reboot/previousreboot.info"; - + // Non-DCM mode (DCM_FLAG=0): Always upload (script line 999: uploadLogOnReboot true) if (ctx->dcm_flag == 0) { should_upload = true; - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Non-DCM mode (dcm_flag=0), will always upload logs\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Non-DCM mode (dcm_flag=0), will always upload logs\n", __FUNCTION__, __LINE__); } else { @@ -1176,19 +1200,19 @@ static int reboot_upload(RuntimeContext* ctx, SessionState* session) } else { RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Could not open reboot reason file: %s\n", __FUNCTION__, __LINE__, reboot_info_path); } - + // Get RFC setting for unscheduled reboot upload via RBUS bool disable_unscheduled_upload = false; if (!rbus_get_bool_param("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.UploadLogsOnUnscheduledReboot.Disable", &disable_unscheduled_upload)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Failed to get UploadLogsOnUnscheduledReboot.Disable RFC, assuming false\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to get UploadLogsOnUnscheduledReboot.Disable RFC, assuming false\n", __FUNCTION__, __LINE__); disable_unscheduled_upload = false; } - + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] uploadLog:%s and UploadLogsOnUnscheduledReboot.Disable RFC: %s\n", __FUNCTION__, __LINE__, ctx->upload_on_reboot ? "true" : "false", disable_unscheduled_upload ? "true" : "false"); - + // Upload if upload_on_reboot is enabled, OR if the reboot is unscheduled // and the UploadLogsOnUnscheduledReboot.Disable RFC does not disable it. // Script logic for the unscheduled reboot path: @@ -1201,16 +1225,16 @@ static int reboot_upload(RuntimeContext* ctx, SessionState* session) // Construct full archive path using session archive filename char archive_path[MAX_PATH_LENGTH]; int written = snprintf(archive_path, sizeof(archive_path), "%s/%s", ctx->prev_log_path, session->archive_file); - + if (written >= (int)sizeof(archive_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Archive path too long\n", __FUNCTION__, __LINE__); return -1; } - + if (!should_upload) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Upload not allowed based on reboot reason and RFC settings\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Upload not allowed based on reboot reason and RFC settings\n", __FUNCTION__, __LINE__); strncpy(session->archive_file, archive_path, sizeof(session->archive_file) - 1); session->archive_file[sizeof(session->archive_file) - 1] = '\0'; @@ -1218,21 +1242,21 @@ static int reboot_upload(RuntimeContext* ctx, SessionState* session) return 0; } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Uploading main logs: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Uploading main logs: %s\n", __FUNCTION__, __LINE__, archive_path); // Upload main logs (session->success is set by execute_upload_cycle) int ret = upload_archive(ctx, session, archive_path); - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Main log upload complete (result=%d)\n", + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Main log upload complete (result=%d)\n", __FUNCTION__, __LINE__, ret); // Upload DRI logs if directory exists (using separate session to avoid state corruption) if (ctx->include_dri && dir_exists(ctx->dri_log_path)) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] DRI log directory exists, uploading DRI logs\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] DRI log directory exists, uploading DRI logs\n", __FUNCTION__, __LINE__); // Upload DRI logs using separate session state @@ -1252,21 +1276,21 @@ static int reboot_upload(RuntimeContext* ctx, SessionState* session) RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] DRI archive path too long\n", __FUNCTION__, __LINE__); } else { dri_ret = upload_archive(ctx, &dri_session, dri_archive); - + // Send telemetry for DRI upload (matches script lines 883, 886) // Script sends SYST_INFO_PDRILogUpload for both success and failure t2_count_notify("SYST_INFO_PDRILogUpload"); - + if (dri_ret == 0) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] DRI log upload succeeded, removing DRI directory\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] DRI log upload succeeded, removing DRI directory\n", __FUNCTION__, __LINE__); remove_directory(ctx->dri_log_path); } else { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] DRI log upload failed\n", __FUNCTION__, __LINE__); } - + // Clean up DRI archive remove_file(dri_archive); } @@ -1275,12 +1299,12 @@ static int reboot_upload(RuntimeContext* ctx, SessionState* session) // Clear old packet captures if (ctx->include_pcap) { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] Clearing old packet captures\n", __FUNCTION__, __LINE__); clear_old_packet_captures(ctx->log_path); } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] REBOOT/NON_DCM: Upload phase complete\n", __FUNCTION__, __LINE__); return ret; @@ -1288,7 +1312,7 @@ static int reboot_upload(RuntimeContext* ctx, SessionState* session) /** * @brief Cleanup phase for REBOOT/NON_DCM strategy - * + * * Shell script equivalent (uploadLogOnReboot lines 893-906): * - Always runs (regardless of upload success) * - Delete tar file @@ -1299,28 +1323,28 @@ static int reboot_upload(RuntimeContext* ctx, SessionState* session) */ static int reboot_cleanup(RuntimeContext* ctx, SessionState* session, bool upload_success) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] REBOOT/NON_DCM: Starting cleanup phase (upload_success=%d)\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] REBOOT/NON_DCM: Starting cleanup phase (upload_success=%d)\n", __FUNCTION__, __LINE__, upload_success); sleep(5); // Delete tar file if (file_exists(session->archive_file)) { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, - "[%s:%d] Removing tar file: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + "[%s:%d] Removing tar file: %s\n", __FUNCTION__, __LINE__, session->archive_file); remove_file(session->archive_file); } // Remove timestamps from filenames (restore original names) - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Removing timestamps from filenames\n", __FUNCTION__, __LINE__); - + int ret = remove_timestamp_from_files(ctx->prev_log_path); if (ret != 0) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Failed to remove timestamps from some files\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to remove timestamps from some files\n", __FUNCTION__, __LINE__); // Continue anyway } @@ -1329,55 +1353,55 @@ static int reboot_cleanup(RuntimeContext* ctx, SessionState* session, bool uploa const char* perm_log_path = perm_log_path_storage; // Create permanent backup directory - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Creating permanent backup directory: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Creating permanent backup directory: %s\n", __FUNCTION__, __LINE__, perm_log_path); - + if (!create_directory(perm_log_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Failed to create permanent backup directory\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Failed to create permanent backup directory\n", __FUNCTION__, __LINE__); return -1; } // Move all files from PREV_LOG_PATH to permanent backup - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Moving files to permanent backup\n", __FUNCTION__, __LINE__); - + ret = move_directory_contents(ctx->prev_log_path, perm_log_path); if (ret != 0) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Failed to move some files to permanent backup\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to move some files to permanent backup\n", __FUNCTION__, __LINE__); } // Clean PREV_LOG_PATH - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Cleaning PREV_LOG_PATH\n", __FUNCTION__, __LINE__); - + clean_directory(ctx->prev_log_path); // Recreate PREV_LOG_BACKUP_PATH for next boot cycle // Script lines 900-902: rm -rf + mkdir -p PREV_LOG_BACKUP_PATH // PREV_LOG_BACKUP_PATH = $LOG_PATH/PreviousLogs_backup/ char prev_log_backup_path[MAX_PATH_LENGTH]; - int written = snprintf(prev_log_backup_path, sizeof(prev_log_backup_path), "%s/PreviousLogs_backup", + int written = snprintf(prev_log_backup_path, sizeof(prev_log_backup_path), "%s/PreviousLogs_backup", ctx->log_path); - + if (written >= (int)sizeof(prev_log_backup_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] PREV_LOG_BACKUP_PATH too long\n", __FUNCTION__, __LINE__); } else { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Recreating PREV_LOG_BACKUP_PATH for next boot: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Recreating PREV_LOG_BACKUP_PATH for next boot: %s\n", __FUNCTION__, __LINE__, prev_log_backup_path); - + if (dir_exists(prev_log_backup_path)) { remove_directory(prev_log_backup_path); } - + if (!create_directory(prev_log_backup_path)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to create PREV_LOG_BACKUP_PATH\n", __FUNCTION__, __LINE__); } } @@ -1387,9 +1411,9 @@ static int reboot_cleanup(RuntimeContext* ctx, SessionState* session, bool uploa if (ctx->dcm_flag == 1 && ctx->upload_on_reboot == 0) { char dcm_upload_list[MAX_PATH_LENGTH]; int written = snprintf(dcm_upload_list, sizeof(dcm_upload_list), "%s/dcm_upload", ctx->log_path); - + if (written >= (int)sizeof(dcm_upload_list)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] DCM upload list path too long\n", __FUNCTION__, __LINE__); } else { FILE* fp = fopen(dcm_upload_list, "a"); @@ -1400,8 +1424,8 @@ static int reboot_cleanup(RuntimeContext* ctx, SessionState* session, bool uploa } } - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] REBOOT/NON_DCM: Cleanup phase complete. Logs backed up to: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] REBOOT/NON_DCM: Cleanup phase complete. Logs backed up to: %s\n", __FUNCTION__, __LINE__, perm_log_path); return 0; diff --git a/uploadstblogs/src/uploadlogsnow.c b/uploadstblogs/src/uploadlogsnow.c index 22b7dd69..2982cb82 100644 --- a/uploadstblogs/src/uploadlogsnow.c +++ b/uploadstblogs/src/uploadlogsnow.c @@ -20,7 +20,7 @@ /** * @file uploadlogsnow.c * @brief UploadLogsNow functionality implementation for logupload binary - * + * * This module provides the C implementation of the original UploadLogsNow.sh script * functionality, integrated as a special mode in the logupload binary. */ @@ -50,12 +50,12 @@ static int write_upload_status(const char* message) { FILE* fp = fopen(STATUS_FILE, "w"); if (!fp) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Failed to open status file: %s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Failed to open status file: %s\n", __FUNCTION__, __LINE__, STATUS_FILE); return -1; } - + time_t now = time(NULL); char timebuf[26]; if (ctime_r(&now, timebuf) != NULL) { @@ -68,8 +68,8 @@ static int write_upload_status(const char* message) fprintf(fp, "%s\n", message); } fclose(fp); - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Status updated: %s\n", __FUNCTION__, __LINE__, message); return 0; } @@ -81,10 +81,10 @@ static int should_exclude_file(const char* filename) { const char* exclude_list[] = { "dcm", - "PreviousLogs_backup", + "PreviousLogs_backup", "PreviousLogs" }; - + for (size_t i = 0; i < sizeof(exclude_list)/sizeof(exclude_list[0]); i++) { if (strcmp(filename, exclude_list[i]) == 0) { return 1; @@ -96,86 +96,86 @@ static int should_exclude_file(const char* filename) /** * @brief Copy all files from source to destination, excluding specified items * @param src_path Source directory path - * @param dest_path Destination directory path + * @param dest_path Destination directory path * @return Number of files successfully copied (>= 0), or -1 on directory open failure * @note Returns 0 for empty directories (this is a valid success case, not an error) */ -static int copy_files_to_dcm_path(const char* src_path, const char* dest_path) +int copy_files_to_dcm_path(const char* src_path, const char* dest_path) { DIR* dir = opendir(src_path); if (!dir) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Failed to open source directory: %s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Failed to open source directory: %s\n", __FUNCTION__, __LINE__, src_path); return -1; } - + struct dirent* entry; int copied_count = 0; - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Copying files from %s to %s\n", + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Copying files from %s to %s\n", __FUNCTION__, __LINE__, src_path, dest_path); - + while ((entry = readdir(dir)) != NULL) { // Skip . and .. if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } - + // Skip excluded files/directories if (should_exclude_file(entry->d_name)) { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, - "[%s:%d] Excluding file: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + "[%s:%d] Excluding file: %s\n", __FUNCTION__, __LINE__, entry->d_name); continue; } - + // Construct full paths char src_file[MAX_PATH_LENGTH]; char dest_file[MAX_PATH_LENGTH]; - + // Check if paths would fit to prevent truncation size_t src_len = strlen(src_path) + 1 + strlen(entry->d_name) + 1; size_t dest_len = strlen(dest_path) + 1 + strlen(entry->d_name) + 1; - + if (src_len > sizeof(src_file) || dest_len > sizeof(dest_file)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Path too long, skipping: %s\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Path too long, skipping: %s\n", __FUNCTION__, __LINE__, entry->d_name); continue; } - + int src_ret = snprintf(src_file, sizeof(src_file), "%s/%s", src_path, entry->d_name); int dest_ret = snprintf(dest_file, sizeof(dest_file), "%s/%s", dest_path, entry->d_name); - + // Additional safety check for snprintf truncation - if (src_ret < 0 || src_ret >= (int)sizeof(src_file) || + if (src_ret < 0 || src_ret >= (int)sizeof(src_file) || dest_ret < 0 || dest_ret >= (int)sizeof(dest_file)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Path formatting failed, skipping: %s\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Path formatting failed, skipping: %s\n", __FUNCTION__, __LINE__, entry->d_name); continue; } - + // Use file operations utility for copy if (copy_file(src_file, dest_file)) { copied_count++; - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, "[%s:%d] Copied: %s\n", __FUNCTION__, __LINE__, entry->d_name); } else { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, - "[%s:%d] Failed to copy: %s\n", + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + "[%s:%d] Failed to copy: %s\n", __FUNCTION__, __LINE__, entry->d_name); } } - + closedir(dir); - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Successfully copied %d files/directories\n", + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Successfully copied %d files/directories\n", __FUNCTION__, __LINE__, copied_count); - + return copied_count; } @@ -185,20 +185,20 @@ static int copy_files_to_dcm_path(const char* src_path, const char* dest_path) int execute_uploadlogsnow_workflow(RuntimeContext* ctx) { if (!ctx) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Invalid context parameter\n", __FUNCTION__, __LINE__); return -1; } char dcm_log_path[MAX_PATH_LENGTH] = {0}; int ret = -1; - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] UploadLogsNow workflow execution started\n", __FUNCTION__, __LINE__); - + // Write initial status write_upload_status("Triggered"); - + // Use DCM_LOG_PATH from context or default if (strlen(ctx->dcm_log_path) > 0) { strncpy(dcm_log_path, ctx->dcm_log_path, sizeof(dcm_log_path) - 1); @@ -207,109 +207,109 @@ int execute_uploadlogsnow_workflow(RuntimeContext* ctx) strncpy(dcm_log_path, DCM_TEMP_DIR, sizeof(dcm_log_path) - 1); dcm_log_path[sizeof(dcm_log_path) - 1] = '\0'; } - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Using LOG_PATH=%s, DCM_LOG_PATH=%s\n", + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Using LOG_PATH=%s, DCM_LOG_PATH=%s\n", __FUNCTION__, __LINE__, ctx->log_path, dcm_log_path); - + // Create DCM_LOG_PATH directory if (!create_directory(dcm_log_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Failed to create DCM_LOG_PATH: %s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Failed to create DCM_LOG_PATH: %s\n", __FUNCTION__, __LINE__, dcm_log_path); write_upload_status("Failed"); return -1; } - + // Copy all log files to DCM_LOG_PATH int copied_files = copy_files_to_dcm_path(ctx->log_path, dcm_log_path); if (copied_files < 0) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to copy files to DCM path\n", __FUNCTION__, __LINE__); write_upload_status("Failed"); goto cleanup; } - + // Check if any files were copied if (copied_files == 0) { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] No files found to upload in directory: %s\n", + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] No files found to upload in directory: %s\n", __FUNCTION__, __LINE__, ctx->log_path); write_upload_status("No files to upload"); ret = 0; // Success, but no files to process goto cleanup; } - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Uploading Logs through SNMP/TR69 Upload\n", __FUNCTION__, __LINE__); - + // Add timestamps to files (using UploadLogsNow-specific exclusions) if (add_timestamp_to_files_uploadlogsnow(dcm_log_path) != 0) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to add timestamps to some files\n", __FUNCTION__, __LINE__); // Continue - not critical for upload } - + // Use existing archive creation function - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Creating archive using archive_manager\n", __FUNCTION__, __LINE__); - + write_upload_status("In progress"); - + // Use the existing ONDEMAND workflow with archive creation SessionState session = {0}; session.strategy = STRAT_ONDEMAND; - + // Update the DCM_LOG_PATH in context to point to our prepared directory strncpy(ctx->dcm_log_path, dcm_log_path, sizeof(ctx->dcm_log_path) - 1); ctx->dcm_log_path[sizeof(ctx->dcm_log_path) - 1] = '\0'; - + // Use existing create_archive function if (create_archive(ctx, &session, dcm_log_path) != 0) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed to create log archive\n", __FUNCTION__, __LINE__); write_upload_status("Failed"); goto cleanup; } - + // Check if archive was created successfully (following RRD pattern) char full_archive_path[MAX_PATH_LENGTH]; int path_ret = snprintf(full_archive_path, sizeof(full_archive_path), "%s/%s", dcm_log_path, session.archive_file); - + // Check for snprintf truncation if (path_ret < 0 || path_ret >= (int)sizeof(full_archive_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Archive path too long: %s/%s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Archive path too long: %s/%s\n", __FUNCTION__, __LINE__, dcm_log_path, session.archive_file); write_upload_status("Failed"); goto cleanup; } - + if (!file_exists(full_archive_path)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, - "[%s:%d] Archive file does not exist: %s\n", + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + "[%s:%d] Archive file does not exist: %s\n", __FUNCTION__, __LINE__, full_archive_path); write_upload_status("Failed"); goto cleanup; } - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] Archive created successfully: %s\n", + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] Archive created successfully: %s\n", __FUNCTION__, __LINE__, full_archive_path); - + // Update session to contain full path for upload functions strncpy(session.archive_file, full_archive_path, sizeof(session.archive_file) - 1); session.archive_file[sizeof(session.archive_file) - 1] = '\0'; - + // Follow RRD upload pattern: decide_paths() then execute_upload_cycle() decide_paths(ctx, &session); if (!execute_upload_cycle(ctx, &session)) { - RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Failed Uploading Logs through - SNMP/TR69\n", __FUNCTION__, __LINE__); write_upload_status("Failed"); ret = -1; } else { - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] Uploaded Logs through - SNMP/TR69\n", __FUNCTION__, __LINE__); write_upload_status("Complete"); ret = 0; @@ -318,17 +318,17 @@ int execute_uploadlogsnow_workflow(RuntimeContext* ctx) cleanup: // Clean up DCM_LOG_PATH if (!remove_directory(dcm_log_path)) { - RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, + RDK_LOG(RDK_LOG_WARN, LOG_UPLOADSTB, "[%s:%d] Failed to cleanup DCM_LOG_PATH\n", __FUNCTION__, __LINE__); } else { - RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, - "[%s:%d] Cleaned up DCM_LOG_PATH: %s\n", + RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, + "[%s:%d] Cleaned up DCM_LOG_PATH: %s\n", __FUNCTION__, __LINE__, dcm_log_path); } - - RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, - "[%s:%d] UploadLogsNow workflow completed with result: %d\n", + + RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, + "[%s:%d] UploadLogsNow workflow completed with result: %d\n", __FUNCTION__, __LINE__, ret); - + return ret; } diff --git a/uploadstblogs/unittest/context_manager_gtest.cpp b/uploadstblogs/unittest/context_manager_gtest.cpp index 96539bc8..51c77555 100755 --- a/uploadstblogs/unittest/context_manager_gtest.cpp +++ b/uploadstblogs/unittest/context_manager_gtest.cpp @@ -62,7 +62,7 @@ class ContextManagerTest : public ::testing::Test { // Set up mock objects g_mockRdkUtils = new MockRdkUtils(); g_mockRbus = new MockRbus(); - + // Clear context memset(&ctx, 0, sizeof(RuntimeContext)); } @@ -73,7 +73,7 @@ class ContextManagerTest : public ::testing::Test { unlink("/tmp/.lastcodebigfail_upl"); unlink("/tmp/.EnableOCSPStapling"); unlink("/tmp/.EnableOCSPCA"); - + delete g_mockRdkUtils; delete g_mockRbus; g_mockRdkUtils = nullptr; @@ -116,12 +116,12 @@ TEST_F(ContextManagerTest, DirectBlocked_FileWithinBlockTime) { TEST_F(ContextManagerTest, DirectBlocked_FileExpired) { CreateTestFileWithAge("/tmp/.lastdirectfail_upl", 90000); // 25 hours ago EXPECT_FALSE(is_direct_blocked(86400)); // 24 hour block time - + // File should be removed EXPECT_EQ(access("/tmp/.lastdirectfail_upl", F_OK), -1); } -// Test is_codebig_blocked function +// Test is_codebig_blocked function TEST_F(ContextManagerTest, CodebigBlocked_NoFile) { unlink("/tmp/.lastcodebigfail_upl"); EXPECT_FALSE(is_codebig_blocked(1800)); @@ -135,7 +135,7 @@ TEST_F(ContextManagerTest, CodebigBlocked_FileWithinBlockTime) { TEST_F(ContextManagerTest, CodebigBlocked_FileExpired) { CreateTestFileWithAge("/tmp/.lastcodebigfail_upl", 2000); // 33+ minutes ago EXPECT_FALSE(is_codebig_blocked(1800)); // 30 minute block time - + // File should be removed EXPECT_EQ(access("/tmp/.lastcodebigfail_upl", F_OK), -1); } @@ -150,35 +150,35 @@ TEST_F(ContextManagerTest, LoadEnvironment_Success) { EXPECT_CALL(*g_mockRdkUtils, getIncludePropertyData(StrEq("LOG_PATH"), _, _)) .WillOnce(DoAll(SetArrayArgument<1>("/opt/test", "/opt/test" + 9), Return(UTILS_SUCCESS))); - + EXPECT_CALL(*g_mockRdkUtils, getIncludePropertyData(StrEq("DIRECT_BLOCK_TIME"), _, _)) .WillOnce(DoAll(SetArrayArgument<1>("43200", "43200" + 6), Return(UTILS_SUCCESS))); - + EXPECT_CALL(*g_mockRdkUtils, getIncludePropertyData(StrEq("CB_BLOCK_TIME"), _, _)) .WillOnce(DoAll(SetArrayArgument<1>("900", "900" + 4), Return(UTILS_SUCCESS))); - + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(StrEq("PROXY_BUCKET"), _, _)) .WillOnce(Return(UTILS_FAIL)); - + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(StrEq("DEVICE_TYPE"), _, _)) .WillOnce(DoAll(SetArrayArgument<1>("mediaclient", "mediaclient" + 11), Return(UTILS_SUCCESS))); - + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(StrEq("BUILD_TYPE"), _, _)) .WillOnce(DoAll(SetArrayArgument<1>("prod", "prod" + 5), Return(UTILS_SUCCESS))); - + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(StrEq("DCM_LOG_PATH"), _, _)) .WillOnce(Return(UTILS_FAIL)); - + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(StrEq("ENABLE_MAINTENANCE"), _, _)) .WillOnce(DoAll(SetArrayArgument<1>("true", "true" + 5), Return(UTILS_SUCCESS))); EXPECT_TRUE(load_environment(&ctx)); - + // Verify loaded values EXPECT_STREQ(ctx.log_path, "/opt/test"); EXPECT_STREQ(ctx.prev_log_path, "/opt/test/PreviousLogs"); @@ -193,12 +193,12 @@ TEST_F(ContextManagerTest, LoadEnvironment_DefaultValues) { // All property calls fail, should use defaults EXPECT_CALL(*g_mockRdkUtils, getIncludePropertyData(_, _, _)) .WillRepeatedly(Return(UTILS_FAIL)); - + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(_, _, _)) .WillRepeatedly(Return(UTILS_FAIL)); EXPECT_TRUE(load_environment(&ctx)); - + // Verify default values EXPECT_STREQ(ctx.log_path, "/opt/logs"); EXPECT_STREQ(ctx.prev_log_path, "/opt/logs/PreviousLogs"); @@ -211,10 +211,10 @@ TEST_F(ContextManagerTest, LoadEnvironment_DefaultValues) { TEST_F(ContextManagerTest, LoadEnvironment_OCSPEnabled) { // Create OCSP marker files CreateTestFile("/tmp/.EnableOCSPStapling"); - + EXPECT_CALL(*g_mockRdkUtils, getIncludePropertyData(_, _, _)) .WillRepeatedly(Return(UTILS_FAIL)); - + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(_, _, _)) .WillRepeatedly(Return(UTILS_FAIL)); @@ -222,6 +222,44 @@ TEST_F(ContextManagerTest, LoadEnvironment_OCSPEnabled) { EXPECT_TRUE(ctx.ocsp_enabled); } +// RDK-C: DCM_SCHEDULED_LOG_COLLECT device-property gating (collect_scheduled_logs) +TEST_F(ContextManagerTest, LoadEnvironment_ScheduledLogCollect_Enabled) { + EXPECT_CALL(*g_mockRdkUtils, getIncludePropertyData(_, _, _)) + .WillRepeatedly(Return(UTILS_FAIL)); + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(_, _, _)) + .WillRepeatedly(Return(UTILS_FAIL)); + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(StrEq("DCM_SCHEDULED_LOG_COLLECT"), _, _)) + .WillOnce(DoAll(SetArrayArgument<1>("true", "true" + 5), + Return(UTILS_SUCCESS))); + + EXPECT_TRUE(load_environment(&ctx)); + EXPECT_TRUE(ctx.collect_scheduled_logs); +} + +TEST_F(ContextManagerTest, LoadEnvironment_ScheduledLogCollect_DisabledWhenFalse) { + EXPECT_CALL(*g_mockRdkUtils, getIncludePropertyData(_, _, _)) + .WillRepeatedly(Return(UTILS_FAIL)); + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(_, _, _)) + .WillRepeatedly(Return(UTILS_FAIL)); + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(StrEq("DCM_SCHEDULED_LOG_COLLECT"), _, _)) + .WillOnce(DoAll(SetArrayArgument<1>("false", "false" + 6), + Return(UTILS_SUCCESS))); + + EXPECT_TRUE(load_environment(&ctx)); + EXPECT_FALSE(ctx.collect_scheduled_logs); +} + +TEST_F(ContextManagerTest, LoadEnvironment_ScheduledLogCollect_DefaultDisabled) { + // Property absent (all device-property reads fail) => default off (STB/broadband parity) + EXPECT_CALL(*g_mockRdkUtils, getIncludePropertyData(_, _, _)) + .WillRepeatedly(Return(UTILS_FAIL)); + EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(_, _, _)) + .WillRepeatedly(Return(UTILS_FAIL)); + + EXPECT_TRUE(load_environment(&ctx)); + EXPECT_FALSE(ctx.collect_scheduled_logs); +} + // Test load_tr181_params function TEST_F(ContextManagerTest, LoadTR181Params_NullContext) { EXPECT_FALSE(load_tr181_params(nullptr)); @@ -230,30 +268,30 @@ TEST_F(ContextManagerTest, LoadTR181Params_NullContext) { TEST_F(ContextManagerTest, LoadTR181Params_RbusInitFail) { EXPECT_CALL(*g_mockRbus, rbus_init()) .WillOnce(Return(false)); - + EXPECT_FALSE(load_tr181_params(&ctx)); } TEST_F(ContextManagerTest, LoadTR181Params_Success) { EXPECT_CALL(*g_mockRbus, rbus_init()) .WillOnce(Return(true)); - + EXPECT_CALL(*g_mockRbus, rbus_get_string_param( StrEq("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.LogUploadEndpoint.URL"), _, _)) .WillOnce(DoAll(SetArrayArgument<1>("https://example.com/upload", "https://example.com/upload" + 27), Return(true))); - + EXPECT_CALL(*g_mockRbus, rbus_get_bool_param( StrEq("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.EncryptCloudUpload.Enable"), _)) .WillOnce(DoAll(SetArgPointee<1>(true), Return(true))); - + EXPECT_CALL(*g_mockRbus, rbus_get_string_param( StrEq("Device.X_RDKCENTRAL-COM_Privacy.PrivacyMode"), _, _)) .WillOnce(DoAll(SetArrayArgument<1>("DO_NOT_SHARE", "DO_NOT_SHARE" + 12), Return(true))); - + EXPECT_TRUE(load_tr181_params(&ctx)); - + // Verify loaded values EXPECT_STREQ(ctx.endpoint_url, "https://example.com/upload"); EXPECT_TRUE(ctx.encryption_enable); @@ -272,24 +310,24 @@ TEST_F(ContextManagerTest, GetMacAddress_ZeroSize) { TEST_F(ContextManagerTest, GetMacAddress_Success) { char mac_buffer[32]; - + EXPECT_CALL(*g_mockRdkUtils, GetEstbMac(_, _)) .WillOnce(DoAll( Invoke([](char* mac_buf, size_t buf_size) -> size_t { strcpy(mac_buf, "AA:BB:CC:DD:EE:FF"); return strlen("AA:BB:CC:DD:EE:FF"); }))); - + EXPECT_TRUE(get_mac_address(mac_buffer, sizeof(mac_buffer))); EXPECT_STREQ(mac_buffer, "AA:BB:CC:DD:EE:FF"); } TEST_F(ContextManagerTest, GetMacAddress_Failure) { char mac_buffer[32]; - + EXPECT_CALL(*g_mockRdkUtils, GetEstbMac(_, _)) .WillOnce(Return(0)); - + EXPECT_FALSE(get_mac_address(mac_buffer, sizeof(mac_buffer))); } @@ -304,7 +342,7 @@ TEST_F(ContextManagerTest, InitContext_Success) { .WillRepeatedly(Return(UTILS_FAIL)); EXPECT_CALL(*g_mockRdkUtils, getDevicePropertyData(_, _, _)) .WillRepeatedly(Return(UTILS_FAIL)); - + // Mock load_tr181_params success EXPECT_CALL(*g_mockRbus, rbus_init()) .WillOnce(Return(true)); @@ -312,7 +350,7 @@ TEST_F(ContextManagerTest, InitContext_Success) { .WillRepeatedly(Return(false)); EXPECT_CALL(*g_mockRbus, rbus_get_bool_param(_, _)) .WillRepeatedly(Return(false)); - + // Mock get_mac_address success EXPECT_CALL(*g_mockRdkUtils, GetEstbMac(_, _)) .WillOnce(DoAll( @@ -320,7 +358,7 @@ TEST_F(ContextManagerTest, InitContext_Success) { strcpy(mac_buf, "AA:BB:CC:DD:EE:FF"); return strlen("AA:BB:CC:DD:EE:FF"); }))); - + EXPECT_TRUE(init_context(&ctx)); } @@ -334,9 +372,9 @@ TEST_F(ContextManagerTest, InitContext_LoadEnvironmentFails) { int main(int argc, char** argv) { // Create test results directory system("mkdir -p " GTEST_DEFAULT_RESULT_FILEPATH); - + // Initialize Google Test ::testing::InitGoogleTest(&argc, argv); - + return RUN_ALL_TESTS(); }