mirror of
https://dev.iopsys.eu/system/sysmngr.git
synced 2026-01-27 18:47:19 +01:00
Added support for DeviceInfo.MemoryStatus.MemoryMonitor. Object
This commit is contained in:
parent
b7a44f16b3
commit
d15e6c6364
6 changed files with 576 additions and 15 deletions
|
|
@ -235,7 +235,7 @@ DMOBJ tDeviceInfoObj[] = {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SYSMNGR_MEMORY_STATUS
|
#ifdef SYSMNGR_MEMORY_STATUS
|
||||||
{"MemoryStatus", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tDeviceInfoMemoryStatusParams, NULL, BBFDM_BOTH},
|
{"MemoryStatus", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, tDeviceInfoMemoryStatusObj, tDeviceInfoMemoryStatusParams, NULL, BBFDM_BOTH},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SYSMNGR_PROCESS_STATUS
|
#ifdef SYSMNGR_PROCESS_STATUS
|
||||||
|
|
|
||||||
530
src/memory.c
530
src/memory.c
|
|
@ -11,30 +11,491 @@
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
#define DEFAULT_POLLING_INTERVAL "60"
|
||||||
|
#define DEFAULT_CRITICAL_RISE_THRESHOLD "80"
|
||||||
|
#define DEFAULT_CRITICAL_FALL_THRESHOLD "60"
|
||||||
|
#define DEFAULT_CRITICAL_MEMORY_LOG_PATH "/var/log/critical_memory.log"
|
||||||
|
|
||||||
|
typedef struct mem_info {
|
||||||
|
unsigned long mem_total;
|
||||||
|
unsigned long mem_free;
|
||||||
|
unsigned long buffers;
|
||||||
|
unsigned long cached;
|
||||||
|
unsigned long sreclaimable;
|
||||||
|
} mem_info;
|
||||||
|
|
||||||
|
typedef struct memory_ctx {
|
||||||
|
struct uloop_timeout memory_timer;
|
||||||
|
bool enable;
|
||||||
|
bool enable_critical_log;
|
||||||
|
unsigned int polling_interval;
|
||||||
|
unsigned int critical_rise_threshold;
|
||||||
|
unsigned int critical_fall_threshold;
|
||||||
|
time_t critical_rise_time;
|
||||||
|
time_t critical_fall_time;
|
||||||
|
char log_file[512];
|
||||||
|
} memory_ctx;
|
||||||
|
|
||||||
|
static memory_ctx g_memory_ctx = {0};
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* COMMON FUNCTIONS
|
||||||
|
**************************************************************/
|
||||||
|
int sysmngr_meminfo(mem_info *info)
|
||||||
|
{
|
||||||
|
FILE *f = NULL;
|
||||||
|
char *key = NULL, *val = NULL;
|
||||||
|
char line[256];
|
||||||
|
|
||||||
|
if ((f = fopen("/proc/meminfo", "r")) == NULL) {
|
||||||
|
BBF_ERR("Failed to open '/proc/meminfo' for reading memory info.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), f)) {
|
||||||
|
key = strtok(line, " :");
|
||||||
|
val = strtok(NULL, " ");
|
||||||
|
|
||||||
|
if (!key || !val)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!strcasecmp(key, "MemTotal"))
|
||||||
|
info->mem_total = atol(val);
|
||||||
|
else if (!strcasecmp(key, "MemFree"))
|
||||||
|
info->mem_free = atol(val);
|
||||||
|
else if (!strcasecmp(key, "Buffers"))
|
||||||
|
info->buffers = atol(val);
|
||||||
|
else if (!strcasecmp(key, "Cached"))
|
||||||
|
info->cached = atol(val);
|
||||||
|
else if (!strcasecmp(key, "SReclaimable"))
|
||||||
|
info->sreclaimable = atol(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int calculate_memory_utilization(void)
|
||||||
|
{
|
||||||
|
mem_info info = {0};
|
||||||
|
|
||||||
|
if (sysmngr_meminfo(&info) != 0) {
|
||||||
|
BBF_ERR("Failed to retrieve memory information for utilization calculation");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long used_mem = info.mem_total - (info.mem_free + info.buffers + info.cached + info.sreclaimable);
|
||||||
|
|
||||||
|
return (unsigned int)((used_mem * 100) / info.mem_total);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_memory_critical_state_event(unsigned int mem_utilization)
|
||||||
|
{
|
||||||
|
struct blob_buf bb = {0};
|
||||||
|
char buf[32] = {0};
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "%u", mem_utilization);
|
||||||
|
|
||||||
|
memset(&bb, 0, sizeof(struct blob_buf));
|
||||||
|
blob_buf_init(&bb, 0);
|
||||||
|
|
||||||
|
blobmsg_add_string(&bb, "name", "Device.DeviceInfo.MemoryStatus.MemoryMonitor.MemoryCriticalState!");
|
||||||
|
|
||||||
|
void *arr = blobmsg_open_array(&bb, "input");
|
||||||
|
|
||||||
|
void *table = blobmsg_open_table(&bb, NULL);
|
||||||
|
blobmsg_add_string(&bb, "path", "MemUtilization");
|
||||||
|
blobmsg_add_string(&bb, "data", buf);
|
||||||
|
blobmsg_add_string(&bb, "type", DMT_TYPE[DMT_UNINT]);
|
||||||
|
blobmsg_close_table(&bb, table);
|
||||||
|
|
||||||
|
blobmsg_close_array(&bb, arr);
|
||||||
|
|
||||||
|
if (sysmngr_ubus_invoke_sync("bbfdm", "notify_event", bb.head, NULL, NULL)) {
|
||||||
|
BBF_ERR("Failed to send 'MemoryCriticalState!' event");
|
||||||
|
} else {
|
||||||
|
BBF_DEBUG("'MemoryCriticalState!' event sent successfully with utilization at %u%%.", mem_utilization);
|
||||||
|
}
|
||||||
|
|
||||||
|
blob_buf_free(&bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_log_file(time_t log_time, bool critical_state)
|
||||||
|
{
|
||||||
|
FILE *log_file = fopen(g_memory_ctx.log_file, "w"); // Write mode, clears log each time
|
||||||
|
if (log_file == NULL) {
|
||||||
|
BBF_ERR("Failed to open log file at '%s'", g_memory_ctx.log_file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(log_file, "=== Memory Critical State %s at %s ===\n",
|
||||||
|
critical_state ? "Reached" : "no longer present", ctime(&log_time));
|
||||||
|
|
||||||
|
const char *commands[] = {
|
||||||
|
"top -b -n 1", // Shows a snapshot of top output, including CPU and memory stats
|
||||||
|
"free", // Shows memory usage statistics in a human-readable format
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; commands[i] != NULL; i++) {
|
||||||
|
FILE *cmd_output = popen(commands[i], "r"); // flawfinder: ignore
|
||||||
|
if (cmd_output == NULL) {
|
||||||
|
fprintf(log_file, "Failed to execute command: %s\n", commands[i]);
|
||||||
|
BBF_ERR("Failed to execute system command: %s", commands[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(log_file, "\nOutput of command: %s\n", commands[i]);
|
||||||
|
char buffer[256];
|
||||||
|
while (fgets(buffer, sizeof(buffer), cmd_output) != NULL) {
|
||||||
|
fprintf(log_file, "%s", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pclose(cmd_output);
|
||||||
|
fprintf(log_file, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(log_file, "=== End of Critical Memory Log ===\n\n");
|
||||||
|
fclose(log_file);
|
||||||
|
|
||||||
|
BBF_DEBUG("Generated memory log file at: '%s'", g_memory_ctx.log_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_memory_monitor(void)
|
||||||
|
{
|
||||||
|
unsigned int mem_utilization = calculate_memory_utilization();
|
||||||
|
char buf[32] = {0};
|
||||||
|
|
||||||
|
if ((mem_utilization > g_memory_ctx.critical_rise_threshold) &&
|
||||||
|
(g_memory_ctx.critical_fall_time >= g_memory_ctx.critical_rise_time)) {
|
||||||
|
|
||||||
|
BBF_INFO("Memory utilization reached critical threshold: %u%%", mem_utilization);
|
||||||
|
|
||||||
|
// Update CriticalRiseTimeStamp to the current time
|
||||||
|
g_memory_ctx.critical_rise_time = time(NULL);
|
||||||
|
snprintf(buf, sizeof(buf), "%ld", g_memory_ctx.critical_rise_time);
|
||||||
|
sysmngr_uci_set("sysmngr", "memory", "critical_rise_time", buf);
|
||||||
|
|
||||||
|
if (g_memory_ctx.enable_critical_log) {
|
||||||
|
// Generate log into the vendor log file referenced by 'VendorLogFileRef' parameter indicating critical condition is reached
|
||||||
|
generate_log_file(g_memory_ctx.critical_rise_time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send 'MemoryCriticalState!' event
|
||||||
|
send_memory_critical_state_event(mem_utilization);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mem_utilization < g_memory_ctx.critical_fall_threshold) &&
|
||||||
|
(g_memory_ctx.critical_rise_time > g_memory_ctx.critical_fall_time)) {
|
||||||
|
|
||||||
|
BBF_INFO("Memory utilization has fallen below critical threshold: %u%%", mem_utilization);
|
||||||
|
|
||||||
|
// Update CriticalFallTimeStamp to the current time
|
||||||
|
g_memory_ctx.critical_fall_time = time(NULL);
|
||||||
|
snprintf(buf, sizeof(buf), "%ld", g_memory_ctx.critical_fall_time);
|
||||||
|
sysmngr_uci_set("sysmngr", "memory", "critical_fall_time", buf);
|
||||||
|
|
||||||
|
if (g_memory_ctx.enable_critical_log) {
|
||||||
|
// Generate log into the vendor log file referenced by 'VendorLogFileRef' parameter indicating that the critical condition is no longer present
|
||||||
|
generate_log_file(g_memory_ctx.critical_fall_time, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BBF_INFO("Next memory monitor check scheduled in %d sec...", g_memory_ctx.polling_interval);
|
||||||
|
uloop_timeout_set(&g_memory_ctx.memory_timer, g_memory_ctx.polling_interval * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void memory_timer_callback(struct uloop_timeout *timeout)
|
||||||
|
{
|
||||||
|
run_memory_monitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_global_memory_ctx(void)
|
||||||
|
{
|
||||||
|
char buf[16] = {0};
|
||||||
|
|
||||||
|
memset(&g_memory_ctx, 0, sizeof(struct memory_ctx));
|
||||||
|
|
||||||
|
g_memory_ctx.memory_timer.cb = memory_timer_callback;
|
||||||
|
|
||||||
|
sysmngr_uci_get("sysmngr", "memory", "enable", "0", buf, sizeof(buf));
|
||||||
|
g_memory_ctx.enable = ((int)strtol(buf, NULL, 10) != 0);
|
||||||
|
BBF_DEBUG("Memory Monitor Config: |Enable| |%d|", g_memory_ctx.enable);
|
||||||
|
|
||||||
|
sysmngr_uci_get("sysmngr", "memory", "enable_critical_log", "0", buf, sizeof(buf));
|
||||||
|
g_memory_ctx.enable_critical_log = ((int)strtol(buf, NULL, 10) != 0);
|
||||||
|
BBF_DEBUG("Memory Monitor Config: |EnableCriticalLog| |%d|", g_memory_ctx.enable_critical_log);
|
||||||
|
|
||||||
|
sysmngr_uci_get("sysmngr", "memory", "polling_interval", DEFAULT_POLLING_INTERVAL, buf, sizeof(buf));
|
||||||
|
g_memory_ctx.polling_interval = strtoul(buf, NULL, 10);
|
||||||
|
BBF_DEBUG("Memory Monitor Config: |PollingInterval| |%lu|", g_memory_ctx.polling_interval);
|
||||||
|
|
||||||
|
sysmngr_uci_get("sysmngr", "memory", "critical_rise_threshold", DEFAULT_CRITICAL_RISE_THRESHOLD, buf, sizeof(buf));
|
||||||
|
g_memory_ctx.critical_rise_threshold = strtoul(buf, NULL, 10);
|
||||||
|
BBF_DEBUG("Memory Monitor Config: |CriticalRiseThreshold| |%lu|", g_memory_ctx.critical_rise_threshold);
|
||||||
|
|
||||||
|
sysmngr_uci_get("sysmngr", "memory", "critical_fall_threshold", DEFAULT_CRITICAL_FALL_THRESHOLD, buf, sizeof(buf));
|
||||||
|
g_memory_ctx.critical_fall_threshold = strtoul(buf, NULL, 10);
|
||||||
|
BBF_DEBUG("Memory Monitor Config: |CriticalFallThreshold| |%lu|", g_memory_ctx.critical_fall_threshold);
|
||||||
|
|
||||||
|
sysmngr_uci_get("sysmngr", "memory", "critical_rise_time", "0", buf, sizeof(buf));
|
||||||
|
g_memory_ctx.critical_rise_time = strtol(buf, NULL, 10);
|
||||||
|
BBF_DEBUG("Memory Monitor Config: |CriticalRiseTimeStamp| |%lu|", g_memory_ctx.critical_rise_time);
|
||||||
|
|
||||||
|
sysmngr_uci_get("sysmngr", "memory", "critical_fall_time", "0", buf, sizeof(buf));
|
||||||
|
g_memory_ctx.critical_fall_time = strtol(buf, NULL, 10);
|
||||||
|
BBF_DEBUG("Memory Monitor Config: |CriticalFallTimeStamp| |%lu|", g_memory_ctx.critical_fall_time);
|
||||||
|
|
||||||
|
sysmngr_uci_get("sysmngr", "memory", "file_path", DEFAULT_CRITICAL_MEMORY_LOG_PATH, g_memory_ctx.log_file, sizeof(g_memory_ctx.log_file));
|
||||||
|
BBF_DEBUG("Memory Monitor Config: |FilePath| |%s|", g_memory_ctx.log_file);
|
||||||
|
if (!file_exists(g_memory_ctx.log_file)) {
|
||||||
|
// Create empty file if it doesn't exist
|
||||||
|
create_empty_file(g_memory_ctx.log_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* EXTERNAL APIS
|
||||||
|
**************************************************************/
|
||||||
|
void sysmngr_memory_init(void)
|
||||||
|
{
|
||||||
|
fill_global_memory_ctx();
|
||||||
|
|
||||||
|
if (!g_memory_ctx.enable) {
|
||||||
|
BBF_INFO("Memory monitoring is disabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BBF_INFO("Memory monitoring is enabled");
|
||||||
|
run_memory_monitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sysmngr_memory_clean(void)
|
||||||
|
{
|
||||||
|
uloop_timeout_cancel(&g_memory_ctx.memory_timer);
|
||||||
|
BBF_INFO("Memory monitoring process stopped");
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* GET & SET PARAM
|
* GET & SET PARAM
|
||||||
**************************************************************/
|
**************************************************************/
|
||||||
static int get_memory_status_total(char* refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
{
|
{
|
||||||
json_object *res = NULL;
|
*value = dmuci_get_option_value_fallback_def("sysmngr", "memory", "enable", "0");
|
||||||
dmubus_call("system", "info", UBUS_ARGS{{}}, 0, &res);
|
|
||||||
DM_ASSERT(res, *value = dmstrdup("0"));
|
|
||||||
char *total = dmjson_get_value(res, 2, "memory", "total");
|
|
||||||
dmasprintf(value, "%lu", DM_STRTOUL(total) / 1024);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_memory_status_free(char* refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
static int set_DeviceInfoMemoryStatusMemoryMonitor_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||||
{
|
{
|
||||||
json_object *res = NULL;
|
bool b;
|
||||||
dmubus_call("system", "info", UBUS_ARGS{{}}, 0, &res);
|
|
||||||
DM_ASSERT(res, *value = dmstrdup("0"));
|
switch (action) {
|
||||||
char *free = dmjson_get_value(res, 2, "memory", "free");
|
case VALUECHECK:
|
||||||
dmasprintf(value, "%lu", DM_STRTOUL(free) / 1024);
|
if (bbfdm_validate_boolean(ctx, value))
|
||||||
|
return FAULT_9007;
|
||||||
|
break;
|
||||||
|
case VALUESET:
|
||||||
|
string_to_bool(value, &b);
|
||||||
|
dmuci_set_value("sysmngr", "memory", "enable", b ? "1" : "0");
|
||||||
|
break;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_memory_status_total_persistent(char* refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_MemUtilization(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
dmasprintf(value, "%u", calculate_memory_utilization());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_PollingInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
*value = dmuci_get_option_value_fallback_def("sysmngr", "memory", "polling_interval", DEFAULT_POLLING_INTERVAL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_DeviceInfoMemoryStatusMemoryMonitor_PollingInterval(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||||
|
{
|
||||||
|
switch (action) {
|
||||||
|
case VALUECHECK:
|
||||||
|
if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1))
|
||||||
|
return FAULT_9007;
|
||||||
|
break;
|
||||||
|
case VALUESET:
|
||||||
|
dmuci_set_value("sysmngr", "memory", "polling_interval", value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_CriticalRiseThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
*value = dmuci_get_option_value_fallback_def("sysmngr", "memory", "critical_rise_threshold", DEFAULT_CRITICAL_RISE_THRESHOLD);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_DeviceInfoMemoryStatusMemoryMonitor_CriticalRiseThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||||
|
{
|
||||||
|
switch (action) {
|
||||||
|
case VALUECHECK:
|
||||||
|
if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,"100"}}, 1))
|
||||||
|
return FAULT_9007;
|
||||||
|
break;
|
||||||
|
case VALUESET:
|
||||||
|
dmuci_set_value("sysmngr", "memory", "critical_rise_threshold", value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_CriticalFallThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
*value = dmuci_get_option_value_fallback_def("sysmngr", "memory", "critical_fall_threshold", DEFAULT_CRITICAL_FALL_THRESHOLD);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_DeviceInfoMemoryStatusMemoryMonitor_CriticalFallThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||||
|
{
|
||||||
|
switch (action) {
|
||||||
|
case VALUECHECK:
|
||||||
|
if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,"100"}}, 1))
|
||||||
|
return FAULT_9007;
|
||||||
|
break;
|
||||||
|
case VALUESET:
|
||||||
|
dmuci_set_value("sysmngr", "memory", "critical_fall_threshold", value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_CriticalRiseTimeStamp(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
char *rise_time = NULL;
|
||||||
|
|
||||||
|
dmuci_get_option_value_string("sysmngr", "memory", "critical_rise_time", &rise_time);
|
||||||
|
|
||||||
|
return dm_time_utc_format(DM_STRTOL(rise_time), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_CriticalFallTimeStamp(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
char *fall_time = NULL;
|
||||||
|
|
||||||
|
dmuci_get_option_value_string("sysmngr", "memory", "critical_fall_time", &fall_time);
|
||||||
|
|
||||||
|
return dm_time_utc_format(DM_STRTOL(fall_time), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_EnableCriticalLog(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
*value = dmuci_get_option_value_fallback_def("sysmngr", "memory", "enable_critical_log", "0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_DeviceInfoMemoryStatusMemoryMonitor_EnableCriticalLog(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case VALUECHECK:
|
||||||
|
if (bbfdm_validate_boolean(ctx, value))
|
||||||
|
return FAULT_9007;
|
||||||
|
break;
|
||||||
|
case VALUESET:
|
||||||
|
string_to_bool(value, &b);
|
||||||
|
dmuci_set_value("sysmngr", "memory", "enable_critical_log", b ? "1" : "0");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_VendorLogFileRef(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
char *file_path = dmuci_get_option_value_fallback_def("sysmngr", "memory", "file_path", DEFAULT_CRITICAL_MEMORY_LOG_PATH);
|
||||||
|
|
||||||
|
if (file_exists(file_path)) {
|
||||||
|
char file_uri[512] = {0};
|
||||||
|
|
||||||
|
// if there is a path, then prepend file:// to it to comply with bbf requirement of file URI
|
||||||
|
snprintf(file_uri, sizeof(file_uri), "file://%s", file_path);
|
||||||
|
|
||||||
|
// get the vendor file path
|
||||||
|
_bbfdm_get_references(ctx, "Device.DeviceInfo.VendorLogFile.", "Name", file_uri, value);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_DeviceInfoMemoryStatusMemoryMonitor_FilePath(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
*value = dmuci_get_option_value_fallback_def("sysmngr", "memory", "file_path", DEFAULT_CRITICAL_MEMORY_LOG_PATH);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_DeviceInfoMemoryStatusMemoryMonitor_FilePath(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||||
|
{
|
||||||
|
char *file_path = dmuci_get_option_value_fallback_def("sysmngr", "memory", "file_path", DEFAULT_CRITICAL_MEMORY_LOG_PATH);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case VALUECHECK:
|
||||||
|
if (bbfdm_validate_string(ctx, value, -1, -1, NULL, NULL))
|
||||||
|
return FAULT_9007;
|
||||||
|
|
||||||
|
// Restriction: The path in `value` must either:
|
||||||
|
// - Start with "/var/log" for non-persistent logs, or
|
||||||
|
// - Start with "/log/" for persistent logs.
|
||||||
|
// Additionally, the path should not contain any '..' sequences
|
||||||
|
// to prevent directory traversal or invalid file paths.
|
||||||
|
if (!((strncmp(value, "/var/log", 8) == 0 || strncmp(value, "/log/", 5) == 0) && !strstr(value, ".."))) {
|
||||||
|
bbfdm_set_fault_message(ctx, "");
|
||||||
|
return FAULT_9007;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VALUESET:
|
||||||
|
if (file_exists(file_path)) {
|
||||||
|
struct uci_section *dmmap_sec = NULL;
|
||||||
|
char file_uri[512] = {0};
|
||||||
|
|
||||||
|
if (rename(file_path, value) != 0) {
|
||||||
|
bbfdm_set_fault_message(ctx, "Can't rename file from '%s' -> '%s'", file_path, value);
|
||||||
|
return FAULT_9007;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update VendorLogFile dmmap section
|
||||||
|
snprintf(file_uri, sizeof(file_uri), "file://%s", file_path);
|
||||||
|
dmmap_sec = get_dup_section_in_dmmap_opt("dmmap", "vendorlog", "log_file", file_uri);
|
||||||
|
|
||||||
|
snprintf(file_uri, sizeof(file_uri), "file://%s", value);
|
||||||
|
dmuci_set_value_by_section(dmmap_sec, "log_file", file_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
dmuci_set_value("sysmngr", "memory", "file_path", value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_memory_status_total(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
mem_info info = {0};
|
||||||
|
|
||||||
|
sysmngr_meminfo(&info);
|
||||||
|
|
||||||
|
dmasprintf(value, "%lu", info.mem_total);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_memory_status_free(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
mem_info info = {0};
|
||||||
|
|
||||||
|
sysmngr_meminfo(&info);
|
||||||
|
|
||||||
|
dmasprintf(value, "%lu", info.mem_free);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_memory_status_total_persistent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
{
|
{
|
||||||
struct statvfs dinfo;
|
struct statvfs dinfo;
|
||||||
|
|
||||||
|
|
@ -48,7 +509,7 @@ static int get_memory_status_total_persistent(char* refparam, struct dmctx *ctx,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_memory_status_free_persistent(char* refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
static int get_memory_status_free_persistent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
{
|
{
|
||||||
struct statvfs dinfo;
|
struct statvfs dinfo;
|
||||||
|
|
||||||
|
|
@ -62,10 +523,51 @@ static int get_memory_status_free_persistent(char* refparam, struct dmctx *ctx,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************
|
||||||
|
* EVENTS
|
||||||
|
*************************************************************/
|
||||||
|
static event_args MemoryCriticalState_event_args = {
|
||||||
|
.name = "", // This field is left empty because we are not listening to any external events, The system now operates within a single unified daemon,
|
||||||
|
// removing the need for separate event listeners. See send_memory_critical_state_event API for details on implementation.
|
||||||
|
.param = (const char *[]) {
|
||||||
|
"MemUtilization",
|
||||||
|
NULL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int get_event_MemoryCriticalState(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
*value = (char *)&MemoryCriticalState_event_args;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**********************************************************************************************************************************
|
/**********************************************************************************************************************************
|
||||||
* OBJ & LEAF DEFINITION
|
* OBJ & LEAF DEFINITION
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
/* *** Device.DeviceInfo.MemoryStatus.MemoryMonitor. *** */
|
||||||
|
DMLEAF tDeviceInfoMemoryStatusMemoryMonitorParams[] = {
|
||||||
|
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type */
|
||||||
|
{"Enable", &DMWRITE, DMT_BOOL, get_DeviceInfoMemoryStatusMemoryMonitor_Enable, set_DeviceInfoMemoryStatusMemoryMonitor_Enable, BBFDM_BOTH},
|
||||||
|
{"MemUtilization", &DMREAD, DMT_UNINT, get_DeviceInfoMemoryStatusMemoryMonitor_MemUtilization, NULL, BBFDM_BOTH},
|
||||||
|
{"PollingInterval", &DMWRITE, DMT_UNINT, get_DeviceInfoMemoryStatusMemoryMonitor_PollingInterval, set_DeviceInfoMemoryStatusMemoryMonitor_PollingInterval, BBFDM_BOTH},
|
||||||
|
{"CriticalRiseThreshold", &DMWRITE, DMT_UNINT, get_DeviceInfoMemoryStatusMemoryMonitor_CriticalRiseThreshold, set_DeviceInfoMemoryStatusMemoryMonitor_CriticalRiseThreshold, BBFDM_BOTH},
|
||||||
|
{"CriticalFallThreshold", &DMWRITE, DMT_UNINT, get_DeviceInfoMemoryStatusMemoryMonitor_CriticalFallThreshold, set_DeviceInfoMemoryStatusMemoryMonitor_CriticalFallThreshold, BBFDM_BOTH},
|
||||||
|
{"CriticalRiseTimeStamp", &DMREAD, DMT_TIME, get_DeviceInfoMemoryStatusMemoryMonitor_CriticalRiseTimeStamp, NULL, BBFDM_BOTH},
|
||||||
|
{"CriticalFallTimeStamp", &DMREAD, DMT_TIME, get_DeviceInfoMemoryStatusMemoryMonitor_CriticalFallTimeStamp, NULL, BBFDM_BOTH},
|
||||||
|
{"EnableCriticalLog", &DMWRITE, DMT_BOOL, get_DeviceInfoMemoryStatusMemoryMonitor_EnableCriticalLog, set_DeviceInfoMemoryStatusMemoryMonitor_EnableCriticalLog, BBFDM_BOTH},
|
||||||
|
{"VendorLogFileRef", &DMREAD, DMT_STRING, get_DeviceInfoMemoryStatusMemoryMonitor_VendorLogFileRef, NULL, BBFDM_BOTH},
|
||||||
|
{"FilePath", &DMWRITE, DMT_STRING, get_DeviceInfoMemoryStatusMemoryMonitor_FilePath, set_DeviceInfoMemoryStatusMemoryMonitor_FilePath, BBFDM_BOTH},
|
||||||
|
{"MemoryCriticalState!", &DMREAD, DMT_EVENT, get_event_MemoryCriticalState, NULL, BBFDM_USP},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
/* *** Device.DeviceInfo.MemoryStatus. *** */
|
/* *** Device.DeviceInfo.MemoryStatus. *** */
|
||||||
|
DMOBJ tDeviceInfoMemoryStatusObj[] = {
|
||||||
|
/* OBJ, permission, addobj, delobj, checkdep, browseinstobj, nextdynamicobj, dynamicleaf, nextobj, leaf, linker, bbfdm_type */
|
||||||
|
{"MemoryMonitor", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tDeviceInfoMemoryStatusMemoryMonitorParams, NULL, BBFDM_BOTH},
|
||||||
|
{0}
|
||||||
|
};
|
||||||
|
|
||||||
DMLEAF tDeviceInfoMemoryStatusParams[] = {
|
DMLEAF tDeviceInfoMemoryStatusParams[] = {
|
||||||
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
|
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
|
||||||
{"Total", &DMREAD, DMT_UNINT, get_memory_status_total, NULL, BBFDM_BOTH},
|
{"Total", &DMREAD, DMT_UNINT, get_memory_status_total, NULL, BBFDM_BOTH},
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
#ifndef __MEMORY_H
|
#ifndef __MEMORY_H
|
||||||
#define __MEMORY_H
|
#define __MEMORY_H
|
||||||
|
|
||||||
|
extern DMOBJ tDeviceInfoMemoryStatusObj[];
|
||||||
extern DMLEAF tDeviceInfoMemoryStatusParams[];
|
extern DMLEAF tDeviceInfoMemoryStatusParams[];
|
||||||
|
|
||||||
|
void sysmngr_memory_init(void);
|
||||||
|
void sysmngr_memory_clean(void);
|
||||||
|
|
||||||
#endif //__MEMORY_H
|
#endif //__MEMORY_H
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,10 @@
|
||||||
#include "processes.h"
|
#include "processes.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SYSMNGR_MEMORY_STATUS
|
||||||
|
#include "memory.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern DM_MAP_OBJ tDynamicObj[];
|
extern DM_MAP_OBJ tDynamicObj[];
|
||||||
|
|
||||||
static void usage(char *prog)
|
static void usage(char *prog)
|
||||||
|
|
@ -36,9 +40,24 @@ static void usage(char *prog)
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void config_reload_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
|
||||||
|
const char *type, struct blob_attr *msg)
|
||||||
|
{
|
||||||
|
BBF_ERR("Reloading sysmngr upon 'sysmngr.reload' event");
|
||||||
|
|
||||||
|
#ifdef SYSMNGR_MEMORY_STATUS
|
||||||
|
sysmngr_memory_clean();
|
||||||
|
sysmngr_memory_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct bbfdm_context bbfdm_ctx = {0};
|
struct bbfdm_context bbfdm_ctx = {0};
|
||||||
|
struct ubus_event_handler ev = {
|
||||||
|
.cb = config_reload_cb,
|
||||||
|
};
|
||||||
int log_level = LOG_ERR;
|
int log_level = LOG_ERR;
|
||||||
int c = 0;
|
int c = 0;
|
||||||
|
|
||||||
|
|
@ -72,9 +91,16 @@ int main(int argc, char **argv)
|
||||||
sysmngr_process_init(&bbfdm_ctx.ubus_ctx);
|
sysmngr_process_init(&bbfdm_ctx.ubus_ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SYSMNGR_MEMORY_STATUS
|
||||||
|
sysmngr_memory_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (bbfdm_ubus_regiter_init(&bbfdm_ctx))
|
if (bbfdm_ubus_regiter_init(&bbfdm_ctx))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (ubus_register_event_handler(&bbfdm_ctx.ubus_ctx, &ev, "sysmngr.reload"))
|
||||||
|
goto out;
|
||||||
|
|
||||||
uloop_run();
|
uloop_run();
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
@ -84,6 +110,10 @@ out:
|
||||||
sysmngr_process_clean(&bbfdm_ctx.ubus_ctx);
|
sysmngr_process_clean(&bbfdm_ctx.ubus_ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SYSMNGR_MEMORY_STATUS
|
||||||
|
sysmngr_memory_clean();
|
||||||
|
#endif
|
||||||
|
|
||||||
closelog();
|
closelog();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
24
src/utils.c
24
src/utils.c
|
|
@ -229,6 +229,30 @@ int sysmngr_uci_delete(struct uci_context *uci_ctx, const char *package, const c
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sysmngr_ubus_invoke_sync(const char *obj, const char *method, struct blob_attr *msg, sysmngr_ubus_cb data_callback, void *callback_args)
|
||||||
|
{
|
||||||
|
uint32_t id;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
struct ubus_context *ubus_ctx = ubus_connect(NULL);
|
||||||
|
if (!ubus_ctx) {
|
||||||
|
BBF_ERR("Failed to connect with ubus, error: '%d'", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ubus_lookup_id(ubus_ctx, obj, &id)) {
|
||||||
|
rc = ubus_invoke(ubus_ctx, id, method, msg, data_callback, callback_args, 5000);
|
||||||
|
} else {
|
||||||
|
BBF_ERR("Failed to lookup ubus object: '%s'", obj);
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ubus_free(ubus_ctx);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int sysmngr_ubus_invoke_async(struct ubus_context *ubus_ctx, const char *obj, const char *method, struct blob_attr *msg,
|
int sysmngr_ubus_invoke_async(struct ubus_context *ubus_ctx, const char *obj, const char *method, struct blob_attr *msg,
|
||||||
sysmngr_ubus_cb data_callback, sysmngr_ubus_async_cb complete_callback)
|
sysmngr_ubus_cb data_callback, sysmngr_ubus_async_cb complete_callback)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ int sysmngr_uci_delete(struct uci_context *uci_ctx, const char *package, const c
|
||||||
typedef void (*sysmngr_ubus_cb)(struct ubus_request *req, int type, struct blob_attr *msg);
|
typedef void (*sysmngr_ubus_cb)(struct ubus_request *req, int type, struct blob_attr *msg);
|
||||||
typedef void (*sysmngr_ubus_async_cb)(struct ubus_request *req, int ret);
|
typedef void (*sysmngr_ubus_async_cb)(struct ubus_request *req, int ret);
|
||||||
|
|
||||||
|
int sysmngr_ubus_invoke_sync(const char *obj, const char *method, struct blob_attr *msg, sysmngr_ubus_cb data_callback, void *callback_args);
|
||||||
int sysmngr_ubus_invoke_async(struct ubus_context *ubus_ctx, const char *obj, const char *method, struct blob_attr *msg,
|
int sysmngr_ubus_invoke_async(struct ubus_context *ubus_ctx, const char *obj, const char *method, struct blob_attr *msg,
|
||||||
sysmngr_ubus_cb data_callback, sysmngr_ubus_async_cb complete_callback);
|
sysmngr_ubus_cb data_callback, sysmngr_ubus_async_cb complete_callback);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue