Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions source/ccsp/components/include/ipc_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ typedef struct _DHCP_MGR_IPV4_MSG
bool isTimeOffsetAssigned;
uint32_t upstreamCurrRate;
uint32_t downstreamCurrRate;
char cOption122[BUFLEN_256];
char cOption67[BUFLEN_64]; //bootfile name
char cTftpServer[BUFLEN_64];
char cHostName[BUFLEN_64];
char cDomainName[BUFLEN_64];
} DHCP_MGR_IPV4_MSG;

typedef struct _DHCP_MGR_IPV6_MSG
Expand Down
14 changes: 14 additions & 0 deletions source/ccsp/include/ccsp_base_api.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* If not stated otherwise in this file or this component's Licenses.txt file the

Check failure on line 2 in source/ccsp/include/ccsp_base_api.h

View workflow job for this annotation

GitHub Actions / call-fossid-workflow / Fossid Annotate PR

FossID License Issue Detected

Source code with 'IETF' license found in local file 'source/ccsp/include/ccsp_base_api.h' (Match: rdkb/components/opensource/ccsp/CcspCommonLibrary/rdkb/components/opensource/ccsp/CcspCommonLibrary/2101, 1344 lines, url: https://code.rdkcentral.com/r/plugins/gitiles/rdkb/components/opensource/ccsp/CcspCommonLibrary/+archive/rdk-dev-2101.tar.gz, file: source/ccsp/include/ccsp_base_api.h)
* following copyright and licenses apply:
*
* Copyright 2015 RDK Management
Expand Down Expand Up @@ -1345,4 +1345,18 @@

int Rbus_to_CCSP_error_mapper(int error_code);
int Rbus2_to_CCSP_error_mapper(int error_code);

void extract_command_output (char *cmd, char *out, int len);
void stop_self_heal_scripts();
void start_self_heal_scripts();
unsigned long get_interval(const char *key, int def_val);
void update_cron_entry(const char *script, unsigned long interval, bool should_run);
void manage_self_heal_cron_state(bool SelfhealCronEnable);
#endif /* CCSP_BASE_API_H */







Comment on lines +1356 to +1362
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple blank lines at the end of the header file serve no purpose and should be removed to maintain clean code style.

Suggested change

Copilot uses AI. Check for mistakes.
133 changes: 133 additions & 0 deletions source/util_api/ccsp_msg_bus/ccsp_base_api.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* If not stated otherwise in this file or this component's Licenses.txt file the

Check failure on line 2 in source/util_api/ccsp_msg_bus/ccsp_base_api.c

View workflow job for this annotation

GitHub Actions / call-fossid-workflow / Fossid Annotate PR

FossID License Issue Detected

Source code with 'IETF' license found in local file 'source/util_api/ccsp_msg_bus/ccsp_base_api.c' (Match: rdkb/components/opensource/ccsp/CcspCommonLibrary/rdkb/components/opensource/ccsp/CcspCommonLibrary/1, 3637 lines, url: https://code.rdkcentral.com/r/plugins/gitiles/rdkb/components/opensource/ccsp/CcspCommonLibrary/+archive/RDKB-TEST-RELEASE-1.tar.gz, file: source/util_api/ccsp_msg_bus/ccsp_base_api.c)

Check failure on line 2 in source/util_api/ccsp_msg_bus/ccsp_base_api.c

View workflow job for this annotation

GitHub Actions / call-fossid-workflow / Fossid Annotate PR

FossID License Issue Detected

Source code with 'IETF' license found in local file 'source/util_api/ccsp_msg_bus/ccsp_base_api.c' (Match: rdkb/components/opensource/ccsp/CcspCommonLibrary/rdkb/components/opensource/ccsp/CcspCommonLibrary/2101, 3633 lines, url: https://code.rdkcentral.com/r/plugins/gitiles/rdkb/components/opensource/ccsp/CcspCommonLibrary/+archive/rdk-dev-2101.tar.gz, file: source/util_api/ccsp_msg_bus/ccsp_base_api.c)
* following copyright and licenses apply:
*
* Copyright 2015 RDK Management
Expand Down Expand Up @@ -48,6 +48,8 @@
#include <ccsp_psm_helper.h>
#include "ccsp_trace.h"

#include "secure_wrapper.h"

/* For AnscEqualString */
#include "ansc_platform.h"

Expand All @@ -69,6 +71,23 @@
#define CCSP_CR_ETHWAN_DEVICE_PROFILE_XML_FILE "/usr/ccsp/cr-ethwan-deviceprofile.xml"
#endif

// Declaring selfheal scripts
//char *SCRIPT_PATH = "/usr/ccsp/tad/";
char *SELF_HEAL_SCRIPTS[] = {
"selfheal_aggressive.sh",
"self_heal_connectivity_test.sh",
"resource_monitor.sh"
};
Comment on lines +76 to +80
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SELF_HEAL_SCRIPTS array is declared as 'char *SELF_HEAL_SCRIPTS[]' which creates mutable string pointers pointing to string literals. This should be 'const char *SELF_HEAL_SCRIPTS[]' to properly indicate that the strings themselves are immutable and to prevent potential undefined behavior from attempts to modify string literals.

Copilot uses AI. Check for mistakes.

//Start/stop cron jobs
typedef struct {
const char *name;
const char *key;
int def_val;
} CronJob;

#define SCRIPT_COUNT (sizeof(SELF_HEAL_SCRIPTS) / sizeof(SELF_HEAL_SCRIPTS[0]))

typedef struct _component_info {
char **list;
int size;
Expand Down Expand Up @@ -3715,3 +3734,117 @@
}
return CCSP_error_code;
}

void extract_command_output (char *cmd, char *out, int len)
{
FILE *fp;
CcspTraceInfo(("%s : Executing command: %s\n", __FUNCTION__, cmd));
out[0] = 0;

fp = popen (cmd, "r");
if (fp)
{
if (fgets (out, len, fp) != NULL)
{
//CID 252175 fix - Parse warning (PW.PARAMETER_HIDDEN)
size_t len_out = strlen (out);
if ((len_out > 0) && (out[len_out - 1] == '\n'))
out[len_out - 1] = 0;
}
pclose (fp);
}
}

/* Start all self-heal scripts */
void start_self_heal_scripts() {
for (size_t i = 0; i < SCRIPT_COUNT; i++) {
CcspTraceWarning(("%s: Starting %s\n", __FUNCTION__, SELF_HEAL_SCRIPTS[i]));
// Uses the shared path and script name
v_secure_system("/usr/ccsp/tad/%s &", SELF_HEAL_SCRIPTS[i]);
}
}
/* Stop all self-heal scripts */
void stop_self_heal_scripts() {
char buf[64], cmd[128];
for (size_t i = 0; i < SCRIPT_COUNT; i++) {
snprintf(cmd, sizeof(cmd), "pidof %s", SELF_HEAL_SCRIPTS[i]);
Comment on lines +3768 to +3770
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The buffer size for 'cmd' (128 bytes) may be insufficient in edge cases. The snprintf constructs "pidof [script_name]", and while current script names are short, there's no validation that script names won't exceed this buffer in the future. Consider using a larger buffer or adding assertions/checks to ensure the script names fit within the allocated buffer size.

Suggested change
char buf[64], cmd[128];
for (size_t i = 0; i < SCRIPT_COUNT; i++) {
snprintf(cmd, sizeof(cmd), "pidof %s", SELF_HEAL_SCRIPTS[i]);
char buf[64], cmd[256];
for (size_t i = 0; i < SCRIPT_COUNT; i++) {
int n = snprintf(cmd, sizeof(cmd), "pidof %s", SELF_HEAL_SCRIPTS[i]);
if (n < 0 || (size_t)n >= sizeof(cmd)) {
CcspTraceWarning(("%s: Command buffer too small for script name '%s'\n", __FUNCTION__, SELF_HEAL_SCRIPTS[i]));
continue;
}

Copilot uses AI. Check for mistakes.
extract_command_output(cmd, buf, sizeof(buf));
CcspTraceInfo(("%s: pidof %s returned: %s\n", __FUNCTION__, SELF_HEAL_SCRIPTS[i], buf));
if (buf[0] == '\0') {
CcspTraceWarning(("%s: %s is not running\n", __FUNCTION__, SELF_HEAL_SCRIPTS[i]));
} else {
CcspTraceWarning(("%s: Stopping %s \n", __FUNCTION__, SELF_HEAL_SCRIPTS[i]));
v_secure_system("kill -9 %s", buf);
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using kill -9 with PIDs obtained from pidof is a potential security risk. The PID in 'buf' comes from shell command output without validation, and if 'pidof' returns multiple PIDs (space-separated), only the first will be killed. Additionally, if a PID is reused between the pidof call and the kill command, an unintended process could be terminated. Consider validating the PID format (digits only) and handling multiple PIDs properly, or use pkill/killall with proper signal handling instead.

Copilot uses AI. Check for mistakes.
Comment on lines +3776 to +3777
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a potential race condition between checking if a script is running (pidof) and killing it. If the process terminates naturally between these two operations, the PID could be reused by another process, leading to killing an unrelated process. While the time window is small, this is a classic TOCTOU (Time-of-check to time-of-use) vulnerability. Consider using more robust process management or checking the process name/path after obtaining the PID.

Suggested change
CcspTraceWarning(("%s: Stopping %s \n", __FUNCTION__, SELF_HEAL_SCRIPTS[i]));
v_secure_system("kill -9 %s", buf);
/* buf may contain multiple PIDs separated by spaces; validate each before killing */
char *saveptr = NULL;
char *pid_str = strtok_r(buf, " ", &saveptr);
int any_killed = 0;
while (pid_str != NULL) {
char proc_path[64];
char cmdline[256];
long pid = strtol(pid_str, NULL, 10);
if (pid > 0) {
snprintf(proc_path, sizeof(proc_path), "/proc/%ld/cmdline", pid);
FILE *fp = fopen(proc_path, "r");
if (fp != NULL) {
size_t nread = fread(cmdline, 1, sizeof(cmdline) - 1, fp);
fclose(fp);
cmdline[nread] = '\0';
/* Verify that this PID still corresponds to the expected script */
if (strstr(cmdline, SELF_HEAL_SCRIPTS[i]) != NULL) {
CcspTraceWarning(("%s: Stopping %s (pid %ld)\n", __FUNCTION__, SELF_HEAL_SCRIPTS[i], pid));
v_secure_system("kill -9 %ld", pid);
any_killed = 1;
} else {
CcspTraceWarning(("%s: Skipping pid %ld for %s: command line does not match\n",
__FUNCTION__, pid, SELF_HEAL_SCRIPTS[i]));
}
} else {
CcspTraceWarning(("%s: Could not open %s for pid %ld; process may have exited\n",
__FUNCTION__, proc_path, pid));
}
}
pid_str = strtok_r(NULL, " ", &saveptr);
}
if (!any_killed) {
CcspTraceWarning(("%s: No matching processes killed for %s\n", __FUNCTION__, SELF_HEAL_SCRIPTS[i]));
}

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using SIGKILL (kill -9) to terminate scripts is overly aggressive and doesn't allow for graceful shutdown. Scripts cannot catch SIGKILL to clean up resources, close files, or remove lock files. Consider using SIGTERM first and only escalating to SIGKILL if the process doesn't terminate after a timeout period.

Suggested change
v_secure_system("kill -9 %s", buf);
v_secure_system("kill %s; sleep 5; pidof %s >/dev/null 2>&1 && kill -9 $(pidof %s)", buf, SELF_HEAL_SCRIPTS[i], SELF_HEAL_SCRIPTS[i]);

Copilot uses AI. Check for mistakes.
}
}
}

/* To fetch syscfg values */
unsigned long get_interval(const char *key, int def_val) {
// Handle fixed intervals (null keys)
if (!key) return (unsigned long)def_val;

FILE *fp = NULL;
char cmd[64];
char buf[32] = {0};
unsigned long result = (unsigned long)def_val;

// Format the command string
snprintf(cmd, sizeof(cmd), "syscfg get %s", key);
Comment on lines +3792 to +3793
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cmd buffer is sized at 64 bytes but there's no length validation for the 'key' parameter. If a very long key name is passed, snprintf could truncate the command string, potentially creating invalid or unintended syscfg commands. Consider adding a check for the key length or using a larger buffer with proper bounds checking.

Suggested change
// Format the command string
snprintf(cmd, sizeof(cmd), "syscfg get %s", key);
/* Validate that the formatted command will fit into cmd */
{
const char *prefix = "syscfg get ";
size_t prefix_len = strlen(prefix);
size_t key_len = strlen(key);
/* Reserve space for prefix, key, and terminating NUL */
if (prefix_len + key_len + 1 > sizeof(cmd)) {
CcspTraceWarning(("%s: syscfg key too long, using default interval\n", __FUNCTION__));
return result;
}
}
// Format the command string
int n = snprintf(cmd, sizeof(cmd), "syscfg get %s", key);
if (n < 0 || (size_t)n >= sizeof(cmd)) {
/* snprintf error or truncation; avoid running a malformed command */
CcspTraceWarning(("%s: failed to format syscfg command, using default interval\n", __FUNCTION__));
return result;
}

Copilot uses AI. Check for mistakes.

// Execute and read output
if ((fp = popen(cmd, "r")) != NULL) {

if (fgets(buf, sizeof(buf), fp) != NULL && buf[0] != '\0' && buf[0] != '\n') {
result = (unsigned long)atol(buf);
Comment on lines +3798 to +3799
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_interval function uses atol() without validating that the syscfg output is a valid number. If syscfg returns non-numeric data or an error message, atol() will return 0, which might not be a valid interval. Consider adding validation to check if the buffer contains only digits (and optional whitespace) before calling atol(), and log a warning if invalid data is detected.

Copilot uses AI. Check for mistakes.
}
pclose(fp);
}

return result;
}

/* To Update Crontab (Removes old, Adds new) */
void update_cron_entry(const char *script, unsigned long interval, bool should_run) {
// We always remove the old entry to avoid duplicates
v_secure_system("crontab -l 2>/dev/null | sed '/%s/d' | crontab -", script);
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sed pattern uses the script name without proper escaping. If a script name contains special regex characters (like dots in the extensions), this could fail to match correctly. Consider using '\Q...\E' or equivalent to escape the script name, or use a more robust approach like 'sed "//usr/ccsp/tad/$script/d"' with proper escaping of forward slashes.

Suggested change
v_secure_system("crontab -l 2>/dev/null | sed '/%s/d' | crontab -", script);
v_secure_system("crontab -l 2>/dev/null | grep -vF '/usr/ccsp/tad/%s' | crontab -", script);

Copilot uses AI. Check for mistakes.
// If should_run is true, we append the new timing
if (should_run) {
v_secure_system("(crontab -l 2>/dev/null; echo '*/%lu * * * * /usr/ccsp/tad/%s') | crontab -",
interval, script);
Comment on lines +3809 to +3814
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The update_cron_entry function performs crontab operations without any error checking. If crontab operations fail (e.g., due to permissions, corrupted crontab, or cron daemon not running), the function silently continues. Consider checking the return value of v_secure_system or implementing some form of error handling to detect and log failures.

Suggested change
// We always remove the old entry to avoid duplicates
v_secure_system("crontab -l 2>/dev/null | sed '/%s/d' | crontab -", script);
// If should_run is true, we append the new timing
if (should_run) {
v_secure_system("(crontab -l 2>/dev/null; echo '*/%lu * * * * /usr/ccsp/tad/%s') | crontab -",
interval, script);
int ret;
/* We always remove the old entry to avoid duplicates */
ret = v_secure_system("crontab -l 2>/dev/null | sed '/%s/d' | crontab -", script);
if (ret != 0) {
CcspTraceError(("update_cron_entry: failed to remove cron entry for script '%s', ret=%d\n",
script, ret));
}
/* If should_run is true, we append the new timing */
if (should_run) {
ret = v_secure_system("(crontab -l 2>/dev/null; echo '*/%lu * * * * /usr/ccsp/tad/%s') | crontab -",
interval, script);
if (ret != 0) {
CcspTraceError(("update_cron_entry: failed to add cron entry for script '%s' "
"(interval=%lu), ret=%d\n",
script, interval, ret));
}

Copilot uses AI. Check for mistakes.
Comment on lines +3811 to +3814
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cron entry format '*/%lu * * * ' may not work correctly for all interval values. The '/N' syntax in cron means "every Nth unit" starting from 0, so intervals don't align with wall-clock times consistently across restarts. For example, */60 in the minute field will only run at minute 0 (once per hour), not every 60 minutes as might be expected. Consider documenting this behavior or using a different scheduling approach if continuous interval-based execution is required.

Suggested change
// If should_run is true, we append the new timing
if (should_run) {
v_secure_system("(crontab -l 2>/dev/null; echo '*/%lu * * * * /usr/ccsp/tad/%s') | crontab -",
interval, script);
// If should_run is true, we append the new timing
if (should_run) {
/*
* Note on cron semantics:
* - "*/N" in the minute field means "every Nth minute starting from 0",
* not "every N minutes from now". For values >= 60 this can be
* surprising (e.g., "*/60 * * * *" effectively runs at minute 0
* of every hour).
*
* We therefore:
* - Use "*/N * * * *" only for 1 <= N <= 59 (minute-based).
* - For N that are multiples of 60, convert to hour/day based
* expressions where appropriate.
*/
if (interval < 1) {
// Non-positive intervals are treated as "do not schedule".
return;
} else if (interval < 60) {
// Run every <interval> minutes.
v_secure_system("(crontab -l 2>/dev/null; echo '*/%lu * * * * /usr/ccsp/tad/%s') | crontab -",
interval, script);
} else if (interval % 60 == 0 && interval < 24 * 60) {
// Run every <hours> hours at minute 0.
unsigned long hours = interval / 60;
v_secure_system("(crontab -l 2>/dev/null; echo '0 */%lu * * * /usr/ccsp/tad/%s') | crontab -",
hours, script);
} else if (interval % (24 * 60) == 0) {
// Run every <days> days at midnight.
unsigned long days = interval / (24 * 60);
v_secure_system("(crontab -l 2>/dev/null; echo '0 0 */%lu * * /usr/ccsp/tad/%s') | crontab -",
days, script);
} else {
// Fallback: keep minute-based "*/N" semantics, with the caveat that
// cron counts from minute 0, not from the time this entry is added.
v_secure_system("(crontab -l 2>/dev/null; echo '*/%lu * * * * /usr/ccsp/tad/%s') | crontab -",
interval, script);
}

Copilot uses AI. Check for mistakes.
}
}

/* function to Manage add/remove of cron jobs */
void manage_self_heal_cron_state(bool SelfhealCronEnable) {
const CronJob self_heal_scripts[] = {
{"self_heal_connectivity_test.sh", "ConnTest_PingInterval", 60},
{"resource_monitor.sh", "resource_monitor_interval", 15},
{"selfheal_aggressive.sh", "AggressiveInterval", 5}
Comment on lines +3821 to +3823
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order of scripts in the manage_self_heal_cron_state arrays (lines 3820-3823) differs from the order in the SELF_HEAL_SCRIPTS global array (lines 76-80). While not strictly a bug, this inconsistency could lead to confusion during maintenance. Consider using the same order in both locations for clarity.

Suggested change
{"self_heal_connectivity_test.sh", "ConnTest_PingInterval", 60},
{"resource_monitor.sh", "resource_monitor_interval", 15},
{"selfheal_aggressive.sh", "AggressiveInterval", 5}
{"selfheal_aggressive.sh", "AggressiveInterval", 5},
{"self_heal_connectivity_test.sh", "ConnTest_PingInterval", 60},
{"resource_monitor.sh", "resource_monitor_interval", 15}

Copilot uses AI. Check for mistakes.
};

const CronJob recovery_scripts[] = {
{"syscfg_recover.sh", NULL, 15},
{"resource_monitor_recover.sh", NULL, 5}
};

if (SelfhealCronEnable) {
// Stop Cron Job of Recovery Scripts
for (int i = 0; i < 2; i++)
update_cron_entry(recovery_scripts[i].name, 0, false);

// Start Cron Jobs of Self-Heal Scripts (using syscfg lookup)
for (int i = 0; i < 3; i++) {
unsigned long val = get_interval(self_heal_scripts[i].key, self_heal_scripts[i].def_val);
update_cron_entry(self_heal_scripts[i].name, val, true);
}
} else {
// Stop Cron Job of Self-Heal Scripts
for (int i = 0; i < 3; i++)
update_cron_entry(self_heal_scripts[i].name, 0, false);

// Start Cron Job of Recovery Scripts (using fixed defaults)
for (int i = 0; i < 2; i++)
Comment on lines +3831 to +3847
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using hardcoded magic numbers (2 and 3) for loop bounds instead of calculating array sizes makes the code brittle and error-prone. If the array sizes change, these loops will not automatically adjust. Use sizeof() calculations like 'sizeof(recovery_scripts)/sizeof(recovery_scripts[0])' or define constants for these sizes to improve maintainability.

Suggested change
if (SelfhealCronEnable) {
// Stop Cron Job of Recovery Scripts
for (int i = 0; i < 2; i++)
update_cron_entry(recovery_scripts[i].name, 0, false);
// Start Cron Jobs of Self-Heal Scripts (using syscfg lookup)
for (int i = 0; i < 3; i++) {
unsigned long val = get_interval(self_heal_scripts[i].key, self_heal_scripts[i].def_val);
update_cron_entry(self_heal_scripts[i].name, val, true);
}
} else {
// Stop Cron Job of Self-Heal Scripts
for (int i = 0; i < 3; i++)
update_cron_entry(self_heal_scripts[i].name, 0, false);
// Start Cron Job of Recovery Scripts (using fixed defaults)
for (int i = 0; i < 2; i++)
const int num_self_heal_scripts = (int)(sizeof(self_heal_scripts) / sizeof(self_heal_scripts[0]));
const int num_recovery_scripts = (int)(sizeof(recovery_scripts) / sizeof(recovery_scripts[0]));
if (SelfhealCronEnable) {
// Stop Cron Job of Recovery Scripts
for (int i = 0; i < num_recovery_scripts; i++)
update_cron_entry(recovery_scripts[i].name, 0, false);
// Start Cron Jobs of Self-Heal Scripts (using syscfg lookup)
for (int i = 0; i < num_self_heal_scripts; i++) {
unsigned long val = get_interval(self_heal_scripts[i].key, self_heal_scripts[i].def_val);
update_cron_entry(self_heal_scripts[i].name, val, true);
}
} else {
// Stop Cron Job of Self-Heal Scripts
for (int i = 0; i < num_self_heal_scripts; i++)
update_cron_entry(self_heal_scripts[i].name, 0, false);
// Start Cron Job of Recovery Scripts (using fixed defaults)
for (int i = 0; i < num_recovery_scripts; i++)

Copilot uses AI. Check for mistakes.
update_cron_entry(recovery_scripts[i].name, recovery_scripts[i].def_val, true);
}
}
Loading