Skip to content

Commit 893b0fe

Browse files
committed
Move ini parsing into config.c
1 parent 6af66f8 commit 893b0fe

File tree

3 files changed

+280
-125
lines changed

3 files changed

+280
-125
lines changed

src/apps.c

Lines changed: 13 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
*/
2020

2121
#include "apps.h"
22-
#define INI_MAX_LINE MAX_APP_CMD_LENGTH
23-
#include "ini.h"
22+
#include "config.h"
2423
#include "log.h"
2524
#include "utils.h"
2625

@@ -133,37 +132,27 @@ bool get_first_heartbeat(int i)
133132

134133
//------------------------------------------------------------------
135134

136-
static time_t file_modified_time(char *path)
137-
{
138-
struct stat attr;
139-
stat(path, &attr);
140-
return attr.st_mtime;
141-
}
142-
143-
bool is_ini_updated()
144-
{
145-
time_t file_last_modified_time = file_modified_time(app_state.ini_file);
146-
return (file_last_modified_time != app_state.ini_last_modified_time);
147-
}
148-
149-
static int check_ini_file(char *path)
135+
int read_ini_file()
150136
{
151-
if(!path || strlen(path) == 0 || strlen(path) >= MAX_APP_CMD_LENGTH)
137+
// Use default ini file if not already set
138+
if(config_validate_file(app_state.ini_file))
152139
{
153-
return 1;
140+
LOGD("Using default ini file %s", INI_FILE);
141+
snprintf(app_state.ini_file, MAX_APP_CMD_LENGTH, "%s", INI_FILE);
154142
}
155143

156-
if(!f_exist(path))
157-
{
158-
return 1;
159-
}
144+
// Use the config module to parse the file
145+
return config_parse_file(app_state.ini_file, apps, MAX_APPS, &app_state);
146+
}
160147

161-
return 0;
148+
bool is_ini_updated()
149+
{
150+
return config_is_file_updated(app_state.ini_file, app_state.ini_last_modified_time);
162151
}
163152

164153
int set_ini_file(char *path)
165154
{
166-
if(check_ini_file(path))
155+
if(config_validate_file(path))
167156
{
168157
LOGE("Invalid path");
169158
return 1;
@@ -174,107 +163,6 @@ int set_ini_file(char *path)
174163
return 0;
175164
}
176165

177-
static int handler(void *user, const char *section, const char *name, const char *value)
178-
{
179-
(void)(user);
180-
static char last_section[MAX_APP_NAME_LENGTH] = {0};
181-
const char *app_prefix = "app:";
182-
183-
// New section detected
184-
if (strcmp(section, last_section) != 0) {
185-
if (strncmp(section, app_prefix, strlen(app_prefix)) == 0) {
186-
if (app_state.app_count < MAX_APPS) {
187-
const char *app_name = section + strlen(app_prefix);
188-
if (*app_name == '\0') {
189-
LOGE("Empty app name in section header: [%s]", section);
190-
return 0; // Error
191-
}
192-
strncpy(apps[app_state.app_count].name, app_name, MAX_APP_NAME_LENGTH - 1);
193-
apps[app_state.app_count].name[MAX_APP_NAME_LENGTH - 1] = '\0';
194-
app_state.app_count++;
195-
} else {
196-
LOGW("MAX_APPS (%d) reached. Ignoring section [%s]", MAX_APPS, section);
197-
}
198-
}
199-
strncpy(last_section, section, sizeof(last_section) - 1);
200-
last_section[sizeof(last_section) - 1] = '\0';
201-
}
202-
203-
// Find current app index
204-
int index = -1;
205-
if (strncmp(section, app_prefix, strlen(app_prefix)) == 0) {
206-
const char *app_name = section + strlen(app_prefix);
207-
for (int i = 0; i < app_state.app_count; i++) {
208-
if (strcmp(apps[i].name, app_name) == 0) {
209-
index = i;
210-
break;
211-
}
212-
}
213-
}
214-
215-
// Process key-value pairs
216-
if (strcmp(section, "processWatchdog") == 0) {
217-
if (strcmp(name, "udp_port") == 0) {
218-
if (!parse_int(value, 1, 65535, &app_state.udp_port)) {
219-
LOGE("Invalid UDP port: %s", value);
220-
return 0;
221-
}
222-
}
223-
} else if (index != -1) { // This is an app section we are tracking
224-
if (strcmp(name, "start_delay") == 0) {
225-
if (!parse_int(value, 0, INT_MAX, &apps[index].start_delay)) {
226-
LOGE("Invalid start_delay for app %s: %s", apps[index].name, value);
227-
return 0;
228-
}
229-
} else if (strcmp(name, "heartbeat_delay") == 0) {
230-
if (!parse_int(value, 0, INT_MAX, &apps[index].heartbeat_delay)) {
231-
LOGE("Invalid heartbeat_delay for app %s: %s", apps[index].name, value);
232-
return 0;
233-
}
234-
} else if (strcmp(name, "heartbeat_interval") == 0) {
235-
if (!parse_int(value, 0, INT_MAX, &apps[index].heartbeat_interval)) {
236-
LOGE("Invalid heartbeat_interval for app %s: %s", apps[index].name, value);
237-
return 0;
238-
}
239-
} else if (strcmp(name, "cmd") == 0) {
240-
snprintf(apps[index].cmd, MAX_APP_CMD_LENGTH, "%s", value);
241-
if (strlen(value) >= MAX_APP_CMD_LENGTH) {
242-
LOGE("Invalid cmd for app %s - longer than %d charachters", apps[index].name, MAX_APP_CMD_LENGTH);
243-
return 0;
244-
}
245-
}
246-
}
247-
248-
return 1;
249-
}
250-
251-
int read_ini_file()
252-
{
253-
memset(apps, 0, sizeof(apps));
254-
app_state.app_count = 0;
255-
app_state.uptime = get_uptime();
256-
app_state.udp_port = UDP_PORT;
257-
258-
// ini_file could have already set by set_ini_file() earlier
259-
if(check_ini_file(app_state.ini_file))
260-
{
261-
LOGD("Using default ini file %s", INI_FILE);
262-
set_ini_file(INI_FILE);
263-
}
264-
265-
LOGD("Reading ini file %s", app_state.ini_file);
266-
267-
if(ini_parse(app_state.ini_file, handler, NULL) < 0)
268-
{
269-
LOGE("Failed to parse INI file %s", app_state.ini_file);
270-
return 1;
271-
}
272-
273-
LOGD("%d processes have found in the ini file %s", app_state.app_count, app_state.ini_file);
274-
app_state.ini_last_modified_time = file_modified_time(app_state.ini_file);
275-
return 0;
276-
}
277-
278166
//------------------------------------------------------------------
279167

280168
bool is_application_running(int i)

src/config.c

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/**
2+
@file config.c
3+
@brief Configuration Management Module
4+
5+
This module handles INI file parsing, validation, and configuration management
6+
for the Process Watchdog application. It provides functions to load, validate,
7+
and monitor configuration files.
8+
9+
@date 2023-01-01
10+
@version 1.0
11+
@author by Eray Ozturk | [email protected]
12+
@url github.com/diffstorm
13+
@license GPL-3 License
14+
*/
15+
16+
#include "config.h"
17+
#define INI_MAX_LINE MAX_APP_CMD_LENGTH
18+
#include "ini.h"
19+
#include "log.h"
20+
#include "utils.h"
21+
22+
#include <stdio.h>
23+
#include <stdlib.h>
24+
#include <stdbool.h>
25+
#include <string.h>
26+
#include <time.h>
27+
#include <sys/stat.h>
28+
#include <errno.h>
29+
#include <limits.h>
30+
31+
//------------------------------------------------------------------
32+
// Private helper functions
33+
//------------------------------------------------------------------
34+
35+
/**
36+
@brief Gets the last modification time of a file.
37+
38+
@param path Path to the file.
39+
@return Last modification time as time_t.
40+
*/
41+
static time_t config_get_file_modified_time(const char *path)
42+
{
43+
struct stat attr;
44+
stat(path, &attr);
45+
return attr.st_mtime;
46+
}
47+
48+
//------------------------------------------------------------------
49+
// Private parsing functions
50+
//------------------------------------------------------------------
51+
52+
/**
53+
@brief INI file handler function for parsing configuration sections and key-value pairs.
54+
55+
@param user User data (unused).
56+
@param section Section name from INI file.
57+
@param name Key name from INI file.
58+
@param value Value from INI file.
59+
@return 1 on success, 0 on error.
60+
*/
61+
static int config_ini_handler(void *user, const char *section, const char *name, const char *value)
62+
{
63+
// Extract apps and state from user data
64+
Application_t *apps = ((void**)user)[0];
65+
AppState_t *state = ((void**)user)[1];
66+
67+
static char last_section[MAX_APP_NAME_LENGTH] = {0};
68+
const char *app_prefix = "app:";
69+
70+
// New section detected
71+
if (strcmp(section, last_section) != 0) {
72+
if (strncmp(section, app_prefix, strlen(app_prefix)) == 0) {
73+
if (state->app_count < MAX_APPS) {
74+
const char *app_name = section + strlen(app_prefix);
75+
if (*app_name == '\0') {
76+
LOGE("Empty app name in section header: [%s]", section);
77+
return 0; // Error
78+
}
79+
strncpy(apps[state->app_count].name, app_name, MAX_APP_NAME_LENGTH - 1);
80+
apps[state->app_count].name[MAX_APP_NAME_LENGTH - 1] = '\0';
81+
state->app_count++;
82+
} else {
83+
LOGW("MAX_APPS (%d) reached. Ignoring section [%s]", MAX_APPS, section);
84+
}
85+
}
86+
strncpy(last_section, section, sizeof(last_section) - 1);
87+
last_section[sizeof(last_section) - 1] = '\0';
88+
}
89+
90+
// Find current app index
91+
int index = -1;
92+
if (strncmp(section, app_prefix, strlen(app_prefix)) == 0) {
93+
const char *app_name = section + strlen(app_prefix);
94+
for (int i = 0; i < state->app_count; i++) {
95+
if (strcmp(apps[i].name, app_name) == 0) {
96+
index = i;
97+
break;
98+
}
99+
}
100+
}
101+
102+
// Process key-value pairs
103+
if (strcmp(section, "processWatchdog") == 0) {
104+
if (strcmp(name, "udp_port") == 0) {
105+
if (!parse_int(value, 1, 65535, &state->udp_port)) {
106+
LOGE("Invalid UDP port: %s", value);
107+
return 0;
108+
}
109+
}
110+
} else if (index != -1) { // This is an app section we are tracking
111+
if (strcmp(name, "start_delay") == 0) {
112+
if (!parse_int(value, 0, INT_MAX, &apps[index].start_delay)) {
113+
LOGE("Invalid start_delay for app %s: %s", apps[index].name, value);
114+
return 0;
115+
}
116+
} else if (strcmp(name, "heartbeat_delay") == 0) {
117+
if (!parse_int(value, 0, INT_MAX, &apps[index].heartbeat_delay)) {
118+
LOGE("Invalid heartbeat_delay for app %s: %s", apps[index].name, value);
119+
return 0;
120+
}
121+
} else if (strcmp(name, "heartbeat_interval") == 0) {
122+
if (!parse_int(value, 0, INT_MAX, &apps[index].heartbeat_interval)) {
123+
LOGE("Invalid heartbeat_interval for app %s: %s", apps[index].name, value);
124+
return 0;
125+
}
126+
} else if (strcmp(name, "cmd") == 0) {
127+
snprintf(apps[index].cmd, MAX_APP_CMD_LENGTH, "%s", value);
128+
if (strlen(value) >= MAX_APP_CMD_LENGTH) {
129+
LOGE("Invalid cmd for app %s - longer than %d charachters", apps[index].name, MAX_APP_CMD_LENGTH);
130+
return 0;
131+
}
132+
}
133+
}
134+
135+
return 1;
136+
}
137+
138+
//------------------------------------------------------------------
139+
// Public interface functions
140+
//------------------------------------------------------------------
141+
142+
int config_validate_file(const char *ini_path)
143+
{
144+
if(!ini_path || strlen(ini_path) == 0 || strlen(ini_path) >= MAX_APP_CMD_LENGTH)
145+
{
146+
return 1;
147+
}
148+
149+
if(!f_exist(ini_path))
150+
{
151+
return 1;
152+
}
153+
154+
return 0;
155+
}
156+
157+
int config_set_file_path(char *path)
158+
{
159+
if(config_validate_file(path))
160+
{
161+
LOGE("Invalid path");
162+
return 1;
163+
}
164+
165+
// Note: This function originally set a global variable app_state.ini_file
166+
// In the new design, the caller should manage the file path
167+
// For now, we just validate and return success
168+
LOGD("INI file path validated: %s", path);
169+
return 0;
170+
}
171+
172+
bool config_is_file_updated(const char *ini_path, time_t last_modified)
173+
{
174+
time_t file_last_modified_time = config_get_file_modified_time(ini_path);
175+
return (file_last_modified_time != last_modified);
176+
}
177+
178+
int config_parse_file(const char *ini_path, Application_t *apps, int max_apps, AppState_t *state)
179+
{
180+
// Initialize the application array and state
181+
memset(apps, 0, sizeof(Application_t) * max_apps);
182+
state->app_count = 0;
183+
state->uptime = get_uptime();
184+
state->udp_port = UDP_PORT;
185+
186+
LOGD("Reading ini file %s", ini_path);
187+
188+
// Prepare user data for the handler
189+
void *user_data[2] = { apps, state };
190+
191+
if(ini_parse(ini_path, config_ini_handler, user_data) < 0)
192+
{
193+
LOGE("Failed to parse INI file %s", ini_path);
194+
return 1;
195+
}
196+
197+
LOGD("%d processes have found in the ini file %s", state->app_count, ini_path);
198+
state->ini_last_modified_time = config_get_file_modified_time(ini_path);
199+
return 0;
200+
}

0 commit comments

Comments
 (0)