Skip to content

Commit 6af66f8

Browse files
committed
Improve ini format for array of processes
1 parent c108974 commit 6af66f8

File tree

6 files changed

+186
-194
lines changed

6 files changed

+186
-194
lines changed

README.md

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,37 +35,35 @@ An example configuration file looks like this:
3535
```ini
3636
[processWatchdog]
3737
udp_port = 12345
38-
n_apps = 4
39-
40-
1_name = Communicator
41-
1_start_delay = 10
42-
1_heartbeat_delay = 60
43-
1_heartbeat_interval = 20
44-
1_cmd = /usr/bin/python test_child.py 1 crash
45-
46-
2_name = Bot
47-
2_start_delay = 20
48-
2_heartbeat_delay = 90
49-
2_heartbeat_interval = 30
50-
2_cmd = /usr/bin/python test_child.py 2 noheartbeat
51-
52-
3_name = Publisher
53-
3_start_delay = 35
54-
3_heartbeat_delay = 70
55-
3_heartbeat_interval = 16
56-
3_cmd = /usr/bin/python test_child.py 3 crash
57-
58-
4_name = Alert
59-
4_start_delay = 35
60-
4_heartbeat_delay = 130
61-
4_heartbeat_interval = 13
62-
4_cmd = /usr/bin/python test_child.py 4 noheartbeat
38+
39+
[app:Communicator]
40+
start_delay = 10
41+
heartbeat_delay = 60
42+
heartbeat_interval = 20
43+
cmd = /usr/bin/python test_child.py 1 crash
44+
45+
[app:Bot]
46+
start_delay = 20
47+
heartbeat_delay = 90
48+
heartbeat_interval = 30
49+
cmd = /usr/bin/python test_child.py 2 noheartbeat
50+
51+
[app:Publisher]
52+
start_delay = 35
53+
heartbeat_delay = 70
54+
heartbeat_interval = 16
55+
cmd = /usr/bin/python test_child.py 3 crash
56+
57+
[app:Alert]
58+
start_delay = 35
59+
heartbeat_delay = 130
60+
heartbeat_interval = 13
61+
cmd = /usr/bin/python test_child.py 4 noheartbeat
6362
```
6463

6564
### Fields
6665
- `udp_port` : The UDP port to expect heartbeats.
67-
- `n_apps` : Number of applications to manage (4 in the example).
68-
- `name` : Name of the application.
66+
- `[app:<AppName>]` : Each application to be monitored should have its own section prefixed with `app:`. `<AppName>` will be used as the name of the application.
6967
- `start_delay` : Delay in seconds before starting the application.
7068
- `heartbeat_delay` : Time in seconds to wait before expecting a heartbeat from the application.
7169
- `heartbeat_interval` : Maximum time period in seconds between heartbeats (`0`:disables heartbeat checks).

config.ini

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
1-
21
[processWatchdog]
32
udp_port = 12345
4-
n_apps = 4
5-
1_name = Communicator
6-
1_start_delay = 10
7-
1_heartbeat_delay = 60
8-
1_heartbeat_interval = 20
9-
1_cmd = /usr/bin/python test_child.py 1 crash
10-
2_name = Bot
11-
2_start_delay = 20
12-
2_heartbeat_delay = 90
13-
2_heartbeat_interval = 30
14-
2_cmd = /usr/bin/python test_child.py 2 noheartbeat
15-
3_name = Publisher
16-
3_start_delay = 35
17-
3_heartbeat_delay = 70
18-
3_heartbeat_interval = 16
19-
3_cmd = /usr/bin/python test_child.py 3 crash
20-
4_name = Alert
21-
4_start_delay = 35
22-
4_heartbeat_delay = 130
23-
4_heartbeat_interval = 13
24-
4_cmd = /usr/bin/python test_child.py 4 noheartbeat
3+
4+
[app:Communicator]
5+
start_delay = 10
6+
heartbeat_delay = 60
7+
heartbeat_interval = 20
8+
cmd = /usr/bin/python test_child.py 1 crash
9+
10+
[app:Bot]
11+
start_delay = 20
12+
heartbeat_delay = 90
13+
heartbeat_interval = 30
14+
cmd = /usr/bin/python test_child.py 2 noheartbeat
15+
16+
[app:Publisher]
17+
start_delay = 35
18+
heartbeat_delay = 70
19+
heartbeat_interval = 16
20+
cmd = /usr/bin/python test_child.py 3 crash
21+
22+
[app:Alert]
23+
start_delay = 35
24+
heartbeat_delay = 130
25+
heartbeat_interval = 13
26+
cmd = /usr/bin/python test_child.py 4 noheartbeat

src/apps.c

Lines changed: 61 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -36,34 +36,7 @@
3636
#include <sys/wait.h>
3737
#include <errno.h>
3838

39-
/**
40-
@struct Application_t
41-
@brief Structure representing an application defined in the ini file.
42-
*/
43-
typedef struct
44-
{
45-
// In the ini file
46-
int start_delay; /**< Delay in seconds before starting the application. */
47-
int heartbeat_delay; /**< Time in seconds to wait before expecting a heartbeat from the application. */
48-
int heartbeat_interval; /**< Maximum time period in seconds between heartbeats. */
49-
char name[MAX_APP_NAME_LENGTH]; /**< Name of the application. */
50-
char cmd[MAX_APP_CMD_LENGTH]; /**< Command to start the application. */
51-
// Not in the ini file
52-
bool started; /**< Flag indicating whether the application has been started. */
53-
bool first_heartbeat; /**< Flag indicating whether the application has sent its first heartbeat. */
54-
int pid; /**< Process ID of the application. */
55-
time_t last_heartbeat; /**< Time when the last heartbeat was received from the application. */
56-
} Application_t;
57-
58-
typedef struct
59-
{
60-
int app_count; /**< Total number of applications found in the ini file. */
61-
int udp_port; /**< UDP port number specified in the ini file. */
62-
char ini_file[MAX_APP_CMD_LENGTH]; /**< Path to the ini file. */
63-
time_t ini_last_modified_time; /**< Last modified time of the ini file. */
64-
time_t uptime; /**< System uptime in seconds. */
65-
int ini_index; /**< Index used to read an array in the ini file. */
66-
} AppState_t;
39+
6740

6841
static Application_t apps[MAX_APPS]; /**< Array of Application_t structures representing applications defined in the ini file. */
6942
static AppState_t app_state = {0};
@@ -204,91 +177,72 @@ int set_ini_file(char *path)
204177
static int handler(void *user, const char *section, const char *name, const char *value)
205178
{
206179
(void)(user);
207-
const char *target_section = "processWatchdog";
208-
char expected_name[INI_MAX_LINE];
209-
210-
if(strcmp(section, target_section) != 0)
211-
{
212-
return 1;
213-
}
214-
215-
// Global parameters
216-
if(strcmp(name, "udp_port") == 0)
217-
{
218-
if(!parse_int(value, 1, 65535, &app_state.udp_port))
219-
{
220-
LOGE("Invalid UDP port: %s", value);
221-
return 0;
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+
}
222198
}
223-
224-
return 1;
225-
}
226-
227-
if(strcmp(name, "n_apps") == 0)
228-
{
229-
if(!parse_int(value, 0, MAX_APPS, &app_state.app_count))
230-
{
231-
LOGE("Invalid n_apps: %s", value);
232-
return 0;
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+
}
233212
}
234-
235-
return 1;
236213
}
237214

238-
// Application parameters
239-
int index = app_state.ini_index;
240-
241-
if(index >= app_state.app_count)
242-
{
243-
return 1;
244-
}
245-
246-
#define GEN_NAME(field) snprintf(expected_name, sizeof(expected_name), "%d_%s", index + 1, field)
247-
248-
if(GEN_NAME("name"), strcmp(name, expected_name) == 0)
249-
{
250-
snprintf(apps[index].name, MAX_APP_NAME_LENGTH, "%s", value);
251-
252-
if(strlen(value) >= MAX_APP_NAME_LENGTH)
253-
{
254-
LOGW("App %d name truncated", index);
255-
}
256-
}
257-
else if(GEN_NAME("start_delay"), strcmp(name, expected_name) == 0)
258-
{
259-
if(!parse_int(value, 0, INT_MAX, &apps[index].start_delay))
260-
{
261-
LOGE("Invalid start_delay for app %d: %s", index, value);
262-
return 0;
263-
}
264-
}
265-
else if(GEN_NAME("heartbeat_delay"), strcmp(name, expected_name) == 0)
266-
{
267-
if(!parse_int(value, 0, INT_MAX, &apps[index].heartbeat_delay))
268-
{
269-
LOGE("Invalid heartbeat_delay for app %d: %s", index, value);
270-
return 0;
271-
}
272-
}
273-
else if(GEN_NAME("heartbeat_interval"), strcmp(name, expected_name) == 0)
274-
{
275-
if(!parse_int(value, 0, INT_MAX, &apps[index].heartbeat_interval))
276-
{
277-
LOGE("Invalid heartbeat_interval for app %d: %s", index, value);
278-
return 0;
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+
}
279222
}
280-
}
281-
else if(GEN_NAME("cmd"), strcmp(name, expected_name) == 0) // this always must be the last one
282-
{
283-
snprintf(apps[index].cmd, MAX_APP_CMD_LENGTH, "%s", value);
284-
285-
if(strlen(value) >= MAX_APP_CMD_LENGTH)
286-
{
287-
LOGE("Invalid cmd for app %d - longer than %d charachters", index, MAX_APP_CMD_LENGTH);
288-
return 0;
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+
}
289245
}
290-
291-
app_state.ini_index++; // Move to next app after processing cmd
292246
}
293247

294248
return 1;
@@ -297,7 +251,6 @@ static int handler(void *user, const char *section, const char *name, const char
297251
int read_ini_file()
298252
{
299253
memset(apps, 0, sizeof(apps));
300-
app_state.ini_index = 0;
301254
app_state.app_count = 0;
302255
app_state.uptime = get_uptime();
303256
app_state.udp_port = UDP_PORT;
@@ -317,11 +270,6 @@ int read_ini_file()
317270
return 1;
318271
}
319272

320-
if(app_state.ini_index != app_state.app_count)
321-
{
322-
LOGW("Config mismatch: Expected %d apps, found %d", app_state.app_count, app_state.ini_index);
323-
}
324-
325273
LOGD("%d processes have found in the ini file %s", app_state.app_count, app_state.ini_file);
326274
app_state.ini_last_modified_time = file_modified_time(app_state.ini_file);
327275
return 0;

src/apps.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,34 @@
3838
#define INI_FILE "config.ini" /**< Default ini file path. */
3939
#define UDP_PORT 12345 /**< Default udp port. */
4040

41+
/**
42+
@struct Application_t
43+
@brief Structure representing an application defined in the ini file.
44+
*/
45+
typedef struct
46+
{
47+
// In the ini file
48+
int start_delay; /**< Delay in seconds before starting the application. */
49+
int heartbeat_delay; /**< Time in seconds to wait before expecting a heartbeat from the application. */
50+
int heartbeat_interval; /**< Maximum time period in seconds between heartbeats. */
51+
char name[MAX_APP_NAME_LENGTH]; /**< Name of the application. */
52+
char cmd[MAX_APP_CMD_LENGTH]; /**< Command to start the application. */
53+
// Not in the ini file
54+
bool started; /**< Flag indicating whether the application has been started. */
55+
bool first_heartbeat; /**< Flag indicating whether the application has sent its first heartbeat. */
56+
int pid; /**< Process ID of the application. */
57+
time_t last_heartbeat; /**< Time when the last heartbeat was received from the application. */
58+
} Application_t;
59+
60+
typedef struct
61+
{
62+
int app_count; /**< Total number of applications found in the ini file. */
63+
int udp_port; /**< UDP port number specified in the ini file. */
64+
char ini_file[MAX_APP_CMD_LENGTH]; /**< Path to the ini file. */
65+
time_t ini_last_modified_time; /**< Last modified time of the ini file. */
66+
time_t uptime; /**< System uptime in seconds. */
67+
} AppState_t;
68+
4169
// Function prototypes
4270

4371
/**
@@ -182,4 +210,4 @@ char *get_app_name(int i);
182210
*/
183211
int get_udp_port();
184212

185-
#endif // APPS_H
213+
#endif // APPS_H

0 commit comments

Comments
 (0)