GCC Code Coverage Report


Directory: src/gate/
File: src/gate/system/services_posix.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 251 325 77.2%
Functions: 22 25 88.0%
Branches: 103 175 58.9%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/system/services.h"
30 #include "gate/debugging.h"
31
32 #if defined(GATE_SYS_POSIX)
33 # define GATE_SYSTEM_SERVICES_POSIX_IMPL 1
34 #endif
35
36
37
38 #if defined(GATE_SYSTEM_SERVICES_POSIX_IMPL)
39
40 #include "gate/streams.h"
41 #include "gate/files.h"
42 #include "gate/platforms.h"
43 #include "gate/processes.h"
44 #include "gate/strings.h"
45 #include "gate/debugging.h"
46
47 #define SCRIPT_VAR_SCRIPT "${GATE_SCRIPT_PATH}" /* init script path */
48 #define SCRIPT_VAR_NAME "${GATE_DAEMON_NAME}" /* name of daemon/service */
49 #define SCRIPT_VAR_DAEMON "${GATE_DAEMON_BIN}" /* path of daemon/service executable binary */
50 #define SCRIPT_VAR_ARGS "${GATE_DAEMON_ARGS}" /* arguments of daemon/service process */
51 #define SCRIPT_VAR_DESCR "${GATE_DAEMON_DESCR}" /* description text of daemon/service */
52 #define SCRIPT_VAR_REQUIRE "${GATE_DAEMON_REQUIRE}" /* names of services requires */
53
54 typedef struct daemon_info_class
55 {
56 char name[128];
57 char description[256];
58 char dependencies[128 + 512];
59 char daemon_path[512];
60 char daemon_args[512];
61 char pid_file[512];
62 } daemon_info_t;
63
64
65 #if defined(GATE_SYS_BSD)
66
67 #if defined(GATE_SYS_OPENBSD)
68 /* OpenBSD */
69 #define RCCTL_PATH "/usr/sbin/rcctl"
70 static char const* bsd_daemon_start[] = { RCCTL_PATH, "start", SCRIPT_VAR_NAME };
71 static char const* bsd_daemon_stop[] = { RCCTL_PATH, "stop", SCRIPT_VAR_NAME };
72 static char const* bsd_daemon_status[] = { RCCTL_PATH, "check", SCRIPT_VAR_NAME };
73 static char const* bsd_daemon_add[] = { "true" };
74 static char const* bsd_daemon_enable[] = { RCCTL_PATH, "enable", SCRIPT_VAR_NAME };
75 static char const* bsd_daemon_disable[] = { RCCTL_PATH, "disable", SCRIPT_VAR_NAME };
76 static char const* bsd_daemon_remove[] = { "true" };
77
78 #elif defined(GATE_SYS_NETBSD)
79
80 /* NetBSD */
81 static char const* bsd_daemon_start[] = { SCRIPT_VAR_SCRIPT, "start" };
82 static char const* bsd_daemon_stop[] = { SCRIPT_VAR_SCRIPT, "stop" };
83 static char const* bsd_daemon_status[] = { SCRIPT_VAR_SCRIPT, "status" };
84 static char const* bsd_daemon_add[] = { "true" };
85 static char const* bsd_daemon_enable[] = { "true" };
86 static char const* bsd_daemon_disable[] = { "true" };
87 static char const* bsd_daemon_remove[] = { "true" };
88
89 #else
90
91 /* FreeBSD */
92 #define SERVICE_PATH "/usr/sbin/rcctl"
93 static char const* bsd_daemon_start[] = { SERVICE_PATH, "start", SCRIPT_VAR_NAME };
94 static char const* bsd_daemon_stop[] = { SERVICE_PATH, "stop", SCRIPT_VAR_NAME };
95 static char const* bsd_daemon_status[] = { SERVICE_PATH, "status", SCRIPT_VAR_NAME };
96 static char const* bsd_daemon_add[] = { "true" };
97 static char const* bsd_daemon_enable[] = { "true" };
98 static char const* bsd_daemon_disable[] = { "true" };
99 static char const* bsd_daemon_remove[] = { "true" };
100
101 #endif
102
103 static char const* bsd_daemon_script_paths[] = { "/etc/rc.d/", "/usr/local/etc/rc.d/" };
104
105 #define posix_cmd_daemon_start bsd_daemon_start
106 #define posix_cmd_daemon_start_count (sizeof(bsd_daemon_start) / sizeof(bsd_daemon_start[0]))
107 #define posix_cmd_daemon_stop bsd_daemon_stop
108 #define posix_cmd_daemon_stop_count (sizeof(bsd_daemon_stop) / sizeof(bsd_daemon_stop[0]))
109 #define posix_cmd_daemon_status bsd_daemon_status
110 #define posix_cmd_daemon_status_count (sizeof(bsd_daemon_status) / sizeof(bsd_daemon_status[0]))
111 #define posix_cmd_daemon_add bsd_daemon_add
112 #define posix_cmd_daemon_add_count (sizeof(bsd_daemon_add) / sizeof(bsd_daemon_add[0]))
113 #define posix_cmd_daemon_enable bsd_daemon_enable
114 #define posix_cmd_daemon_enable_count (sizeof(bsd_daemon_enable) / sizeof(bsd_daemon_enable[0]))
115 #define posix_cmd_daemon_disable bsd_daemon_disable
116 #define posix_cmd_daemon_disable_count (sizeof(bsd_daemon_disable) / sizeof(bsd_daemon_disable[0]))
117 #define posix_cmd_daemon_remove bsd_daemon_remove
118 #define posix_cmd_daemon_remove_count (sizeof(bsd_daemon_remove) / sizeof(bsd_daemon_remove[0]))
119
120 #define posix_init_script_paths bsd_daemon_script_paths
121 #define posix_init_script_paths_count (sizeof(bsd_daemon_script_paths) / sizeof(bsd_daemon_script_paths[0]))
122
123 typedef struct bsd_script_info_class
124 {
125 char name[128];
126 char descr[128];
127 char require[256];
128 char command[256];
129 char command_args[256];
130 char pid_file[256];
131 } bsd_script_info_t;
132
133
134 /* static gate_string_t const bsd_provides_token = GATE_STRING_INIT_STATIC("# PROVIDE:"); */
135
136 static gate_string_t const bsd_require_token = GATE_STRING_INIT_STATIC("# REQUIRE:");
137 static gate_string_t const bsd_name_token = GATE_STRING_INIT_STATIC("name=");
138 static gate_string_t const bsd_desc_token = GATE_STRING_INIT_STATIC("desc=");
139
140 #if defined(GATE_SYS_OPENBSD)
141 static gate_string_t const bsd_command_token = GATE_STRING_INIT_STATIC("daemon=");
142 static gate_string_t const bsd_command_args_token = GATE_STRING_INIT_STATIC("daemon_flags=");
143 #else
144 static gate_string_t const bsd_command_token = GATE_STRING_INIT_STATIC("command=");
145 static gate_string_t const bsd_command_args_token = GATE_STRING_INIT_STATIC("command_args=");
146 #endif
147 static gate_string_t const bsd_pidfile_token = GATE_STRING_INIT_STATIC("pidfile=");
148
149 static void extract_line_data_on_match(gate_string_t const* line, gate_string_t const* start_token, char* dest_buffer, gate_size_t dest_buffer_len)
150 {
151 if (gate_string_starts_with(line, start_token))
152 {
153 gate_str_print_text(dest_buffer, dest_buffer_len, &line->str[start_token->length], line->length - start_token->length);
154 }
155 }
156
157 static void optimize_extracted_field(char* ptr, gate_size_t capacity)
158 {
159 static char const trimmable[] = " \"\t";
160 static gate_size_t const trimmable_count = 3;
161 gate_size_t length = gate_str_length_max(ptr, capacity);
162 gate_size_t pos;
163
164 pos = gate_str_find_first_not_of(ptr, length, &trimmable[0], trimmable_count, 0);
165 if (pos == GATE_STR_NPOS)
166 {
167 ptr[0] = 0;
168 return;
169 }
170 else if (pos > 0)
171 {
172 //abc45678
173 length -= pos;
174 gate_mem_move(&ptr[0], &ptr[pos], length);
175 ptr[length] = 0;
176 }
177
178 pos = gate_str_find_last_not_of(ptr, length, &trimmable[0], trimmable_count);
179 if (pos != GATE_STR_NPOS)
180 {
181 ptr[pos + 1] = 0;
182 }
183 }
184
185 static gate_result_t get_bsd_script_info(gate_string_t const* script_file_path, bsd_script_info_t* ptr_info)
186 {
187 gate_result_t ret = GATE_RESULT_FAILED;
188 gate_filestream_t* fs = NULL;
189 char line_buffer[GATE_MAX_COPYBUFFER_LENGTH];
190 gate_size_t line_len;
191 gate_string_t line;
192
193 do
194 {
195 gate_mem_clear(ptr_info, sizeof(bsd_script_info_t));
196 ret = gate_file_openstream(script_file_path, GATE_STREAM_OPEN_READ, &fs);
197 GATE_BREAK_IF_FAILED(ret);
198
199 for (;;)
200 {
201 gate_mem_clear(line_buffer, sizeof(line_buffer));
202 ret = gate_stream_read_line((gate_stream_t*)fs, line_buffer, sizeof(line_buffer), &line_len);
203 GATE_BREAK_IF_FAILED(ret);
204 if (line_len == 0)
205 {
206 break;
207 }
208 gate_string_create_static_len(&line, line_buffer, line_len);
209 gate_string_trim(&line, &line);
210
211 extract_line_data_on_match(&line, &bsd_require_token, ptr_info->require, sizeof(ptr_info->require));
212 extract_line_data_on_match(&line, &bsd_name_token, ptr_info->name, sizeof(ptr_info->name));
213 extract_line_data_on_match(&line, &bsd_desc_token, ptr_info->descr, sizeof(ptr_info->descr));
214 extract_line_data_on_match(&line, &bsd_command_token, ptr_info->command, sizeof(ptr_info->command));
215 extract_line_data_on_match(&line, &bsd_command_args_token, ptr_info->command_args, sizeof(ptr_info->command_args));
216 extract_line_data_on_match(&line, &bsd_pidfile_token, ptr_info->pid_file, sizeof(ptr_info->pid_file));
217 }
218
219 if (gate_str_length(ptr_info->name) == 0)
220 {
221 gate_file_extract_path(script_file_path->str, script_file_path->length,
222 ptr_info->name, sizeof(ptr_info->name),
223 NULL, 0);
224 }
225 optimize_extracted_field(ptr_info->require, sizeof(ptr_info->require));
226 optimize_extracted_field(ptr_info->name, sizeof(ptr_info->name));
227 optimize_extracted_field(ptr_info->descr, sizeof(ptr_info->descr));
228 optimize_extracted_field(ptr_info->command, sizeof(ptr_info->command));
229 optimize_extracted_field(ptr_info->command_args, sizeof(ptr_info->command_args));
230 optimize_extracted_field(ptr_info->pid_file, sizeof(ptr_info->pid_file));
231 } while (0);
232
233 if (fs)
234 {
235 gate_object_release(fs);
236 }
237 return ret;
238 }
239
240 static gate_result_t extract_daemon_script_info(gate_string_t const* script_file_path, daemon_info_t* info)
241 {
242 gate_result_t ret;
243 bsd_script_info_t script_info;
244
245 do
246 {
247 gate_mem_clear(info, sizeof(daemon_info_t));
248 ret = get_bsd_script_info(script_file_path, &script_info);
249 GATE_BREAK_IF_FAILED(ret);
250
251 gate_str_print_text(info->name, sizeof(info->name), script_info.name, gate_str_length(script_info.name));
252 gate_str_print_text(info->description, sizeof(info->description), script_info.descr, gate_str_length(script_info.descr));
253 gate_str_print_text(info->daemon_path, sizeof(info->daemon_path), script_info.command, gate_str_length(script_info.command));
254 gate_str_print_text(info->daemon_args, sizeof(info->daemon_args), script_info.command_args, gate_str_length(script_info.command_args));
255 gate_str_print_text(info->dependencies, sizeof(info->dependencies), script_info.require, gate_str_length(script_info.require));
256 gate_str_print_text(info->pid_file, sizeof(info->pid_file), script_info.pid_file, gate_str_length(script_info.pid_file));
257
258 /*
259 //netbsd + freebsd:
260 "# PROVIDE: abcd";
261 "# REQUIRE: xyz";
262 "name=\"abcd\"";
263 "desc=\"abc daemon\"";
264 "command=\"/usr/bin/${name}\"";
265 "command_args=\"-x -y\"";
266 "pidfile=\"/var/run/${name}.pid\"";
267
268 //openbsd
269 "daemon=\"";
270 "daemon_flags=\"";
271 "daemon_use=\"";
272 //ret = parse_bsd_init_script_file((gate_stream_t*)ptr_stream, &script_info);
273 //GATE_BREAK_IF_FAILED(ret);
274 */
275 } while (0);
276 return ret;
277 }
278
279 static char const* bsd_init_script_lines[] = {
280 "#!/bin/sh",
281 "#",
282 "#",
283 "",
284 "# PROVIDE: " SCRIPT_VAR_NAME,
285 "# REQUIRE: " SCRIPT_VAR_REQUIRE,
286 "",
287 "# OpenGATE.at simple init script for: " SCRIPT_VAR_NAME,
288 #if defined(GATE_SYS_OPENBSD)
289 "daemon=\"" SCRIPT_VAR_DAEMON "\"",
290 "daemon_flags=\"" SCRIPT_VAR_ARGS "\"",
291 #else
292 "command=\"" SCRIPT_VAR_DAEMON "\"",
293 "command_args=\"" SCRIPT_VAR_ARGS "\"",
294 #endif
295 "name=\"" SCRIPT_VAR_NAME "\"",
296 "desc=\"" SCRIPT_VAR_DESCR "\"",
297 "pidfile=\"/var/run/" SCRIPT_VAR_NAME ".pid\"",
298 "",
299 "gate_daemon_start() {",
300 #if defined(GATE_SYS_OPENBSD)
301 " ${daemon} ${daemon_flags}",
302 #else
303 " ${command} ${command_args}",
304 #endif
305 "}",
306 "gate_daemon_check() {",
307 " if [ -f ${pidfile} ]; then",
308 " read PID <${pidfile}",
309 " if ps -p ${PID} > /dev/null 2>&1; then",
310 " echo \"${name} is running\"",
311 " return 0",
312 " fi",
313 " fi",
314 " echo \"${name} is NOT running\"",
315 " return 1",
316 "}",
317 "gate_daemon_stop() {",
318 " if [ -f ${pidfile} ]; then",
319 " read PID <${pidfile}",
320 " rm -f ${pidfile}",
321 " if ps -p ${PID} > /dev/null 2>&1; then",
322 " kill -s TERM ${PID}",
323 " echo \"Stop request sent\"",
324 " return 0",
325 " fi",
326 " fi",
327 " echo \"Stop request NOT performed\"",
328 " return 1",
329 "}",
330 "",
331 #if defined(GATE_SYS_OPENBSD)
332 ". /etc/rc.d/rc.subr",
333 "rc_start() {",
334 " gate_daemon_start",
335 " return",
336 "}",
337 "rc_check() {",
338 " gate_daemon_check",
339 " return",
340 "}",
341 "rc_stop() {",
342 " gate_daemon_stop",
343 " return",
344 "}",
345 "rc_cmd $1",
346 #elif defined(GATE_SYS_NETBSD)
347 "$_rc_subr_loaded . /etc/rc.subr",
348 "start_cmd=\"gate_daemon_start\"",
349 "stop_cmd=\"gate_daemon_stop\"",
350 "load_rc_config $name",
351 "run_rc_command \"$1\"",
352 #else
353 ". /etc/rc.subr",
354 "start_cmd=\"gate_daemon_start\"",
355 "stop_cmd=\"gate_daemon_stop\"",
356 "load_rc_config $name",
357 "run_rc_command \"$1\"",
358 #endif
359 ""
360 };
361
362 #define posix_daemon_script_lines bsd_init_script_lines
363 #define posix_daemon_script_lines_count (sizeof(bsd_init_script_lines) / sizeof(bsd_init_script_lines[0]))
364
365 #else
366
367 /* LINUX */
368
369 static char const* linux_init_start[] = { SCRIPT_VAR_SCRIPT, "start" };
370 static char const* linux_init_stop[] = { SCRIPT_VAR_SCRIPT, "stop" };
371 static char const* linux_init_status[] = { SCRIPT_VAR_SCRIPT, "status" };
372 static char const* linux_init_add_daemon[] = { "/sbin/update-rc.d", SCRIPT_VAR_NAME, "defaults" };
373 static char const* linux_init_enable_daemon[] = { "/sbin/update-rc.d", SCRIPT_VAR_NAME, "enable" };
374 static char const* linux_init_disable_daemon[] = { "/sbin/update-rc.d", SCRIPT_VAR_NAME, "disable" };
375 static char const* linux_init_remove_daemon[] = { "/sbin/update-rc.d", SCRIPT_VAR_NAME, "remove" };
376
377 static char const* linux_init_script_paths[] = { "/etc/init.d/" };
378
379 #define posix_cmd_daemon_start linux_init_start
380 #define posix_cmd_daemon_start_count (sizeof(linux_init_start) / sizeof(linux_init_start[0]))
381 #define posix_cmd_daemon_stop linux_init_stop
382 #define posix_cmd_daemon_stop_count (sizeof(linux_init_stop) / sizeof(linux_init_stop[0]))
383 #define posix_cmd_daemon_status linux_init_status
384 #define posix_cmd_daemon_status_count (sizeof(linux_init_status) / sizeof(linux_init_status[0]))
385 #define posix_cmd_daemon_add linux_init_add_daemon
386 #define posix_cmd_daemon_add_count (sizeof(linux_init_add_daemon) / sizeof(linux_init_add_daemon[0]))
387 #define posix_cmd_daemon_enable linux_init_enable_daemon
388 #define posix_cmd_daemon_enable_count (sizeof(linux_init_enable_daemon) / sizeof(linux_init_enable_daemon[0]))
389 #define posix_cmd_daemon_disable linux_init_disable_daemon
390 #define posix_cmd_daemon_disable_count (sizeof(linux_init_disable_daemon) / sizeof(linux_init_disable_daemon[0]))
391 #define posix_cmd_daemon_remove linux_init_remove_daemon
392 #define posix_cmd_daemon_remove_count (sizeof(linux_init_remove_daemon) / sizeof(linux_init_remove_daemon[0]))
393 #define posix_init_script_paths linux_init_script_paths
394 #define posix_init_script_paths_count (sizeof(linux_init_script_paths) / sizeof(linux_init_script_paths[0]))
395
396
397
398 static char const* linux_systemd_start[] = { "systemctl", "start", SCRIPT_VAR_NAME };
399 static char const* linux_systemd_stop[] = { "systemctl", "stop", SCRIPT_VAR_NAME };
400 static char const* linux_systemd_status[] = { "systemctl", "status", SCRIPT_VAR_NAME };
401
402
403 static gate_string_t const token_begin_init_info = GATE_STRING_INIT_STATIC("### BEGIN INIT INFO");
404 static gate_string_t const token_end_init_info = GATE_STRING_INIT_STATIC("### END INIT INFO");
405
406 static gate_string_t const token_hashtag = GATE_STRING_INIT_STATIC("#");
407
408 static gate_string_t const token_init_info_provides = GATE_STRING_INIT_STATIC("Provides");
409 static gate_string_t const token_init_info_req_start = GATE_STRING_INIT_STATIC("Required-Start");
410 static gate_string_t const token_init_info_req_stop = GATE_STRING_INIT_STATIC("Required-Stop");
411 static gate_string_t const token_init_info_def_start = GATE_STRING_INIT_STATIC("Default-Start");
412 static gate_string_t const token_init_info_def_stop = GATE_STRING_INIT_STATIC("Default-Stop");
413 static gate_string_t const token_init_info_short_descr = GATE_STRING_INIT_STATIC("Short-Description");
414 static gate_string_t const token_init_info_description = GATE_STRING_INIT_STATIC("Description");
415 static gate_string_t const token_init_info_daemon_path = GATE_STRING_INIT_STATIC("Daemon-Path");
416 static gate_string_t const token_init_info_pid_file = GATE_STRING_INIT_STATIC("Pid-File");
417
418 static gate_string_t const token_var_daemon = GATE_STRING_INIT_STATIC("DAEMON=");
419 /* static gate_string_t const token_var_agent = GATE_STRING_INIT_STATIC("AGENT="); */
420 /* static gate_string_t const token_var_pidfile = GATE_STRING_INIT_STATIC("PIDFILE="); */
421
422
423 typedef struct linux_init_script_info_class
424 {
425 char provides[128];
426 char default_start[64];
427 char default_stop[64];
428 char required_start[256];
429 char required_stop[256];
430 char short_description[256];
431 char description[256];
432 char daemon_path[256];
433 char pid_file[256];
434 } linux_init_script_info_t;
435
436 14 static gate_result_t parse_linux_init_script_file(gate_stream_t* stream, linux_init_script_info_t* info)
437 {
438 14 gate_result_t ret = GATE_RESULT_OK;
439 char line_buffer[1024];
440 gate_size_t received;
441 gate_string_t str_line;
442 14 gate_bool_t in_init_header = false;
443 14 gate_bool_t init_header_completed = false;
444 gate_string_t str_key;
445 gate_string_t str_value;
446 gate_size_t pos;
447
448 14 gate_mem_clear(info, sizeof(linux_init_script_info_t));
449
450
1/2
✓ Branch 0 taken 1715 times.
✗ Branch 1 not taken.
1715 while (GATE_SUCCEEDED(ret))
451 {
452 1715 ret = gate_stream_read_line(stream, line_buffer, sizeof(line_buffer), &received);
453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1715 times.
1715 GATE_BREAK_IF_FAILED(ret);
454
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1701 times.
1715 if (received == 0)
455 {
456 14 break;
457 }
458 1701 gate_string_create_static_len(&str_line, line_buffer, received);
459 1701 gate_string_trim(&str_line, &str_line);
460
2/2
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 1561 times.
1701 if (gate_string_is_empty(&str_line))
461 {
462 140 continue; /* skip empty lines */
463 }
464
465
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 1309 times.
1561 if (!init_header_completed)
466 {
467
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 119 times.
252 if (!in_init_header)
468 {
469
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 119 times.
133 if (gate_string_starts_with(&str_line, &token_begin_init_info))
470 {
471 14 in_init_header = true;
472 }
473 else
474 {
475 119 continue;
476 }
477 }
478 else
479 {
480
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 105 times.
119 if (gate_string_starts_with(&str_line, &token_end_init_info))
481 {
482 14 init_header_completed = true;
483 }
484
1/2
✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
105 else if (gate_string_starts_with(&str_line, &token_hashtag))
485 {
486 /* parse init script header entries */
487 105 pos = gate_string_char_pos(&str_line, ':', 1);
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
105 if (pos == GATE_STR_NPOS)
489 {
490 continue;
491 }
492 105 gate_string_substr(&str_key, &str_line, 1, pos - 1);
493 105 gate_string_substr(&str_value, &str_line, pos + 1, GATE_STR_NPOS);
494 105 gate_string_trim(&str_key, &str_key);
495 105 gate_string_trim(&str_value, &str_value);
496
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 91 times.
105 if (gate_string_starts_with(&str_key, &token_init_info_provides)) GATE_STRING_TO_BUFFER(&str_value, info->provides);
497
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 77 times.
91 else if (gate_string_starts_with(&str_key, &token_init_info_req_start)) GATE_STRING_TO_BUFFER(&str_value, info->required_start);
498
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 63 times.
77 else if (gate_string_starts_with(&str_key, &token_init_info_req_stop)) GATE_STRING_TO_BUFFER(&str_value, info->required_stop);
499
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 49 times.
63 else if (gate_string_starts_with(&str_key, &token_init_info_def_start)) GATE_STRING_TO_BUFFER(&str_value, info->default_start);
500
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 35 times.
49 else if (gate_string_starts_with(&str_key, &token_init_info_def_stop)) GATE_STRING_TO_BUFFER(&str_value, info->default_stop);
501
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 21 times.
35 else if (gate_string_starts_with(&str_key, &token_init_info_short_descr)) GATE_STRING_TO_BUFFER(&str_value, info->short_description);
502
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 14 times.
21 else if (gate_string_starts_with(&str_key, &token_init_info_description)) GATE_STRING_TO_BUFFER(&str_value, info->description);
503
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 else if (gate_string_starts_with(&str_key, &token_init_info_daemon_path)) GATE_STRING_TO_BUFFER(&str_value, info->daemon_path);
504
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 else if (gate_string_starts_with(&str_key, &token_init_info_pid_file)) GATE_STRING_TO_BUFFER(&str_value, info->pid_file);
505 14 else continue;
506 }
507 else
508 {
509 continue;
510 }
511 }
512 } /*if(!init_header_completed)*/
513 else
514 {
515
2/2
✓ Branch 1 taken 609 times.
✓ Branch 2 taken 700 times.
1309 if (gate_str_is_empty(info->daemon_path))
516 {
517
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 602 times.
609 if (gate_string_starts_with(&str_line, &token_var_daemon))
518 {
519 7 gate_string_substr(&str_value, &str_line, token_var_daemon.length, GATE_STR_NPOS);
520 7 gate_string_trim(&str_value, &str_value);
521 7 GATE_STRING_TO_BUFFER(&str_value, info->daemon_path);
522 }
523
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 602 times.
602 else if (gate_string_starts_with(&str_line, &token_var_daemon))
524 {
525 gate_string_substr(&str_value, &str_line, token_var_daemon.length, GATE_STR_NPOS);
526 gate_string_trim(&str_value, &str_value);
527 GATE_STRING_TO_BUFFER(&str_value, info->daemon_path);
528 }
529 }
530
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1295 times.
1309 if (gate_str_is_empty(info->pid_file))
531 {
532 14 gate_string_substr(&str_value, &str_line, token_var_daemon.length, GATE_STR_NPOS);
533 14 gate_string_trim(&str_value, &str_value);
534
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (str_value.length > 2)
535 {
536
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
14 if ((str_value.str[0] == '\"') && (str_value.str[str_value.length - 1] == '\"'))
537 {
538 ++str_value.str;
539 str_value.length -= 2;
540 }
541 }
542 14 GATE_STRING_TO_BUFFER(&str_value, info->pid_file);
543 }
544 }
545 }
546 14 return ret;
547 }
548
549 14 static gate_result_t extract_daemon_script_info(gate_string_t const* script_file_path, daemon_info_t* info)
550 {
551 gate_result_t ret;
552 14 gate_filestream_t* ptr_stream = NULL;
553 linux_init_script_info_t script_info;
554 do
555 {
556 14 gate_mem_clear(&script_info, sizeof(script_info));
557 14 ret = gate_file_openstream(script_file_path, GATE_STREAM_OPEN_READ, &ptr_stream);
558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 GATE_BREAK_IF_FAILED(ret);
559
560 14 ret = parse_linux_init_script_file((gate_stream_t*)ptr_stream, &script_info);
561
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 GATE_BREAK_IF_FAILED(ret);
562
563 14 gate_str_print_text(info->name, sizeof(info->name), script_info.provides, gate_str_length(script_info.provides));
564 14 gate_str_print_text(info->description, sizeof(info->description), script_info.description, gate_str_length(script_info.description));
565 14 gate_str_print_text(info->daemon_path, sizeof(info->daemon_path), script_info.daemon_path, gate_str_length(script_info.daemon_path));
566 14 gate_str_print_text(info->pid_file, sizeof(info->pid_file), script_info.pid_file, gate_str_length(script_info.pid_file));
567 14 gate_str_print_text(info->dependencies, sizeof(info->dependencies), script_info.required_start, gate_str_length(script_info.required_start));
568 } while (0);
569
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (ptr_stream)
570 {
571 14 gate_object_release(ptr_stream);
572 }
573 14 return ret;
574 }
575
576 static char const* linux_init_script_lines[] = {
577 "#!/bin/sh",
578 "### BEGIN INIT INFO",
579 "# Provides: " SCRIPT_VAR_NAME,
580 "# Required-Start: $remote_fs $syslog",
581 "# Required-Stop: $remote_fs $syslog",
582 "# Default-Start: 2 3 4 5",
583 "# Default-Stop: 0 1 6",
584 "# Short-Description: " SCRIPT_VAR_DESCR,
585 "# Description: " SCRIPT_VAR_DESCR,
586 "### END INIT INFO",
587 "",
588 "# Author: OpenGATE Framework",
589 "#",
590 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
591 "NAME=\"" SCRIPT_VAR_NAME "\"",
592 "DAEMON=\"" SCRIPT_VAR_DAEMON "\"",
593 "DAEMON_ARGS=\"" SCRIPT_VAR_ARGS "\"",
594 "PIDFILE=\"/var/run/$NAME.pid\"",
595 "TMPPIDFILE=\"/tmp/$NAME.pid\"",
596 "SCRIPTNAME=\"/etc/init.d/$NAME\"",
597 "export SYSTEMD_NO_WRAP=1",
598 "export SYSTEMCTL_SKIP_REDIRECT=1",
599 "",
600 "[ -x \"$DAEMON\" ] || exit 0",
601 "[ -r /etc/default/$NAME ] && . /etc/default/$NAME",
602 "[ -r /lib/init/vars.sh ] && . /lib/init/vars.sh",
603 "[ -r /lib/lsb/init-functions ] && . /lib/lsb/init-functions",
604 "[ -r /etc/init.d/functions ] && . /etc/init.d/functions",
605 "",
606 "is_pid_running() {",
607 " if ps -p $1 > /dev/null 2>&1; then",
608 " return 0",
609 " else",
610 " return 1",
611 " fi;",
612 "}",
613 "",
614 "do_stop() {",
615 " if [ -f $PIDFILE ]; then",
616 " read PID <$PIDFILE",
617 " fi",
618 " rm -f $PIDFILE",
619 " if [ -z \"$PID\" ]; then",
620 " return 0",
621 " fi",
622 " if is_pid_running $PID; then",
623 " echo \"Stopping $NAME (PID $PID).\"",
624 " kill -s TERM $PID",
625 " else",
626 " echo \"$NAME (PID $PID) stopped.\"",
627 " return 0",
628 " fi",
629 " COUNTER=0",
630 " while [ $COUNTER -lt 50 ]; do",
631 " if is_pid_running $PID;",
632 " then",
633 " sleep 0.1",
634 " COUNTER=$((COUNTER+1))",
635 " else",
636 " COUNTER=$((COUNTER+50))",
637 " fi",
638 " done",
639 " if is_pid_running $PID; then",
640 " echo \"Killing $NAME (PID $PID).\"",
641 " kill -s KILL $PID",
642 " fi",
643 " echo \"$NAME (PID $PID) stopped.\"",
644 " return 0",
645 "}",
646 "",
647 "do_start() {",
648 " echo \"Starting $NAME\"",
649 " $DAEMON $DAEMON_ARGS >/dev/null 2>&1 &",
650 " sleep 1.0",
651 " echo \"$NAME start completed.\"",
652 " exit 0",
653 "}",
654 "",
655 "do_statuscheck() {",
656 " if [ -f $PIDFILE ]",
657 " then",
658 " read PID <$PIDFILE",
659 " if [ -z \"$PID\" ]",
660 " then",
661 " echo \"$NAME is not running.\"",
662 " rm -f $PIDFILE > /dev/null",
663 " return 3",
664 " fi",
665 " if is_pid_running $PID;",
666 " then",
667 " echo \"$NAME (PID $PID) is running.\"",
668 " return 0",
669 " else",
670 " echo \"$NAME is not running.\"",
671 " rm -f $PIDFILE > /dev/null",
672 " return 3",
673 " fi",
674 " else",
675 " echo \"$NAME is not running.\"",
676 " return 3",
677 " fi",
678 "}",
679 "",
680 "case \"$1\" in",
681 " start)",
682 " do_start",
683 " ;;",
684 " stop)",
685 " do_stop",
686 " ;;",
687 " force-reload|reload|force-restart|restart)",
688 " do_stop",
689 " do_start",
690 " ;;",
691 " status)",
692 " do_statuscheck",
693 " ;;",
694 " *)",
695 " echo \"Usage: /etc/init.d/eleasvc{start|stop|restart|status}\"",
696 " exit 1",
697 " ;;",
698 "esac",
699 ""
700 };
701
702 #define posix_daemon_script_lines linux_init_script_lines
703 #define posix_daemon_script_lines_count (sizeof(linux_init_script_lines) / sizeof(linux_init_script_lines[0]))
704
705 #endif /* LINUX */
706
707 9 static char const* posix_get_script_path()
708 {
709 gate_size_t ndx;
710
711
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 for (ndx = 0; ndx != posix_init_script_paths_count; ++ndx)
712 {
713 gate_string_t path;
714 9 gate_string_create_static(&path, posix_init_script_paths[ndx]);
715
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 if (gate_file_dir_exists(&path) == GATE_RESULT_OK)
716 {
717 9 return posix_init_script_paths[ndx];
718 }
719 }
720 return NULL;
721 }
722
723 2 static gate_string_t* posix_create_script_file_path(gate_string_t const* service_name, gate_string_t* script_file_path)
724 {
725 2 char const* script_path = posix_get_script_path();
726 gate_string_t path;
727
728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!script_path)
729 {
730 return NULL;
731 }
732
733 2 gate_string_create_static(&path, script_path);
734 2 return gate_file_build_path_string(script_file_path, &path, service_name);
735 }
736
737
738 typedef struct var_mapping
739 {
740 char const* script_var;
741 gate_string_t const* script_value;
742 } var_mapping_t;
743
744 141 static gate_string_t* expand_script_variables(
745 gate_string_t const* entry,
746 var_mapping_t const* mappings, gate_size_t mappings_count,
747 gate_string_t* out_entry)
748 {
749 gate_size_t ndx;
750
751 gate_strbuilder_t builder;
752 141 gate_strbuilder_create(&builder, 64);
753 141 gate_strbuilder_append_string(&builder, entry);
754
755
2/2
✓ Branch 0 taken 528 times.
✓ Branch 1 taken 141 times.
669 for (ndx = 0; ndx != mappings_count; ++ndx)
756 {
757 528 char const* script_var = mappings[ndx].script_var;
758 528 gate_string_t const* script_value = mappings[ndx].script_value;
759 528 gate_size_t len = gate_str_length(script_var);
760 528 gate_size_t pos = gate_strbuilder_str_pos(&builder, script_var, len, 0);
761
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 515 times.
528 if (pos != GATE_STR_NPOS)
762 {
763 13 gate_strbuilder_replace(&builder, pos, len, gate_string_ptr(script_value, 0), gate_string_length(script_value));
764 }
765 }
766
767 141 gate_strbuilder_to_string(&builder, out_entry);
768 141 gate_strbuilder_release(&builder);
769 141 return out_entry;
770 }
771
772 7 static gate_size_t create_command_args(
773 char const* const* in_args, gate_size_t in_args_count,
774 gate_string_t const* daemon_name, gate_string_t const* script_path,
775 gate_string_t* out_args, gate_size_t out_arg_capacity)
776 {
777 gate_size_t ndx;
778 7 var_mapping_t mappings[] =
779 {
780 { SCRIPT_VAR_NAME, daemon_name },
781 { SCRIPT_VAR_SCRIPT, script_path }
782 };
783
784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (in_args_count > out_arg_capacity)
785 {
786 in_args_count = out_arg_capacity;
787 }
788
789
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7 times.
25 for (ndx = 0; ndx != in_args_count; ++ndx)
790 {
791 18 char const* item = in_args[ndx];
792 gate_string_t arg;
793 18 gate_string_create_static(&arg, item);
794 18 expand_script_variables(&arg, mappings, sizeof(mappings) / sizeof(mappings[0]), &out_args[ndx]);
795 }
796 7 return in_args_count;
797 }
798
799 1 static gate_size_t create_start_command_args(
800 gate_string_t const* daemon_name, gate_string_t const* script_path,
801 gate_string_t* out_args, gate_size_t out_arg_capacity)
802 {
803 1 return create_command_args(
804 posix_cmd_daemon_start, posix_cmd_daemon_start_count,
805 daemon_name, script_path, out_args, out_arg_capacity);
806 }
807
808 1 static gate_size_t create_stop_command_args(
809 gate_string_t const* daemon_name, gate_string_t const* script_path,
810 gate_string_t* out_args, gate_size_t out_arg_capacity)
811 {
812 1 return create_command_args(
813 posix_cmd_daemon_stop, posix_cmd_daemon_stop_count,
814 daemon_name, script_path, out_args, out_arg_capacity);
815 }
816
817 1 static gate_size_t create_status_command_args(
818 gate_string_t const* daemon_name, gate_string_t const* script_path,
819 gate_string_t* out_args, gate_size_t out_arg_capacity)
820 {
821 1 return create_command_args(
822 posix_cmd_daemon_status, posix_cmd_daemon_status_count,
823 daemon_name, script_path, out_args, out_arg_capacity);
824 }
825
826 1 static gate_size_t create_add_daemon_command_args(
827 gate_string_t const* daemon_name, gate_string_t const* script_path,
828 gate_string_t* out_args, gate_size_t out_arg_capacity)
829 {
830 1 return create_command_args(
831 posix_cmd_daemon_add, posix_cmd_daemon_add_count,
832 daemon_name, script_path, out_args, out_arg_capacity);
833 }
834
835 1 static gate_size_t create_enable_daemon_command_args(
836 gate_string_t const* daemon_name, gate_string_t const* script_path,
837 gate_string_t* out_args, gate_size_t out_arg_capacity)
838 {
839 1 return create_command_args(
840 posix_cmd_daemon_enable, posix_cmd_daemon_enable_count,
841 daemon_name, script_path, out_args, out_arg_capacity);
842 }
843
844 1 static gate_size_t create_disable_daemon_command_args(
845 gate_string_t const* daemon_name, gate_string_t const* script_path,
846 gate_string_t* out_args, gate_size_t out_arg_capacity)
847 {
848 1 return create_command_args(
849 posix_cmd_daemon_disable, posix_cmd_daemon_disable_count,
850 daemon_name, script_path, out_args, out_arg_capacity);
851 }
852
853 1 static gate_size_t create_remove_daemon_command_args(
854 gate_string_t const* daemon_name, gate_string_t const* script_path,
855 gate_string_t* out_args, gate_size_t out_arg_capacity)
856 {
857 1 return create_command_args(
858 posix_cmd_daemon_remove, posix_cmd_daemon_remove_count,
859 daemon_name, script_path, out_args, out_arg_capacity);
860 }
861
862
863 gate_result_t posix_service_enum(gate_service_enum_callback_t callback, void* user_param)
864 {
865 gate_result_t ret = GATE_RESULT_FAILED;
866 char const* posix_script_path = posix_get_script_path();
867 gate_string_t script_path;
868 gate_file_dirreader_t dir_reader;
869 char filepath[GATE_MAX_FILEPATH_LENGTH];
870 gate_size_t filepath_len;
871 gate_string_t script_file;
872 daemon_info_t daemon_info;
873 gate_service_t service;
874 gate_enumint_t access_bits;
875
876 do
877 {
878 if (!posix_script_path)
879 {
880 ret = GATE_RESULT_NOTAVAILABLE;
881 break;
882 }
883
884 gate_string_create_static(&script_path, posix_script_path);
885 ret = gate_file_dir_open(&script_path, &dir_reader);
886 GATE_BREAK_IF_FAILED(ret);
887
888 if (!callback)
889 {
890 /* no callback, no iteration required */
891 break;
892 }
893
894 while (0 != (filepath_len = gate_file_dir_read(&dir_reader, &filepath[0], sizeof(filepath), false)))
895 {
896 gate_string_create_static(&script_file, filepath);
897 ret = gate_file_get_attributes(&script_file, NULL, &access_bits);
898 if (GATE_FAILED(ret))
899 {
900 continue;
901 }
902 if (!GATE_FLAG_ENABLED(access_bits, GATE_FILEENTRY_ACCESS_OWNEREXECUTE))
903 {
904 /* only executable files can be init scripts */
905 continue;
906 }
907 ret = extract_daemon_script_info(&script_file, &daemon_info);
908 if (GATE_FAILED(ret))
909 {
910 continue;
911 }
912 gate_mem_clear(&service, sizeof(service));
913
914 gate_str_print_text(service.name, sizeof(service.name), daemon_info.name, sizeof(daemon_info.name));
915 gate_str_print_text(service.description, sizeof(service.description), daemon_info.description, sizeof(daemon_info.description));
916 gate_file_extract_path(filepath, filepath_len, service.address, sizeof(service.address), NULL, 0);
917 /* gate_str_print_text(service.address, sizeof(service.address), filepath, filepath_len); */
918 service.flags = 0;
919 if (!callback(&service, user_param))
920 {
921 break;
922 }
923 }
924 gate_file_dir_close(&dir_reader);
925 } while (0);
926
927 return ret;
928 }
929
930 7 static gate_result_t posix_resolve_script(gate_string_t const* service_name, gate_string_t* ptr_script_path, daemon_info_t* ptr_daemon_info)
931 {
932 7 gate_result_t ret = GATE_RESULT_FAILED;
933 7 char const* posix_script_path = posix_get_script_path();
934 gate_string_t script_path;
935 gate_file_dirreader_t dir_reader;
936 char filepath[GATE_MAX_FILEPATH_LENGTH];
937 gate_size_t filepath_len;
938 gate_string_t script_file;
939 daemon_info_t daemon_info;
940 gate_enumint_t access_bits;
941
942 do
943 {
944
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 if (gate_string_is_empty(service_name))
945 {
946 ret = GATE_RESULT_INVALIDARG;
947 break;
948 }
949
950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!posix_script_path)
951 {
952 ret = GATE_RESULT_NOTAVAILABLE;
953 break;
954 }
955
956 7 gate_string_create_static(&script_path, posix_script_path);
957 7 ret = gate_file_dir_open(&script_path, &dir_reader);
958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 GATE_BREAK_IF_FAILED(ret);
959
960 7 ret = GATE_RESULT_NOMATCH;
961
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 while (0 != (filepath_len = gate_file_dir_read(&dir_reader, &filepath[0], sizeof(filepath), false)))
962 {
963 14 gate_string_create_static(&script_file, filepath);
964 14 ret = gate_file_get_attributes(&script_file, NULL, &access_bits);
965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (GATE_FAILED(ret))
966 {
967 continue;
968 }
969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (!GATE_FLAG_ENABLED(access_bits, GATE_FILEENTRY_ACCESS_OWNEREXECUTE))
970 {
971 /* only executable files can be init scripts */
972 continue;
973 }
974 14 ret = extract_daemon_script_info(&script_file, &daemon_info);
975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (GATE_FAILED(ret))
976 {
977 continue;
978 }
979
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 7 times.
14 if (!gate_string_equals_str(service_name, daemon_info.name))
980 {
981 7 continue;
982 }
983
984
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ptr_script_path)
985 {
986 7 gate_string_create(ptr_script_path, filepath, filepath_len);
987 }
988
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ptr_daemon_info)
989 {
990 7 gate_mem_copy(ptr_daemon_info, &daemon_info, sizeof(daemon_info));
991 }
992 7 ret = GATE_RESULT_OK;
993 7 break;
994 }
995 7 gate_file_dir_close(&dir_reader);
996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (GATE_FAILED(ret))
997 {
998 ret = GATE_RESULT_NOTAVAILABLE;
999 }
1000 } while (0);
1001
1002 7 return ret;
1003 }
1004
1005 gate_result_t gate_services_enum(gate_service_enum_callback_t callback, void* user_param)
1006 {
1007 return posix_service_enum(callback, user_param);
1008 }
1009
1010
1011 7 static gate_result_t run_process_with_output_callback(
1012 gate_string_t const* program,
1013 gate_string_t const* args,
1014 gate_size_t args_count,
1015 gate_service_message_callback_t msg_callback, void* user_param,
1016 int* exit_code)
1017 {
1018 7 gate_result_t ret = GATE_RESULT_FAILED;
1019 7 gate_enumint_t start_flags = GATE_PROCESS_START_NOINHERIT | GATE_PROCESS_START_NEWTERMINAL;
1020 7 gate_process_handle_t proc_handle = NULL;
1021 7 gate_process_stream_t* proc_stream = NULL;
1022 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
1023 7 gate_size_t buffer_used = 0;
1024 gate_string_t msg;
1025
1026 do
1027 {
1028 7 ret = gate_process_start(program, args, args_count, NULL, NULL, 0, start_flags, &proc_handle, NULL, &proc_stream);
1029
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 GATE_BREAK_IF_FAILED(ret);
1030
1031
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (proc_stream == NULL)
1032 {
1033 break;
1034 }
1035
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 while (GATE_SUCCEEDED(ret))
1036 {
1037 8 ret = gate_stream_read(proc_stream, buffer, sizeof(buffer), &buffer_used);
1038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 GATE_BREAK_IF_FAILED(ret);
1039
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
8 if (buffer_used == 0)
1040 {
1041 /* end of process stream reached */
1042 3 break;
1043 }
1044
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (msg_callback)
1045 {
1046 4 gate_string_create_static_len(&msg, buffer, buffer_used);
1047 4 msg_callback(&msg, user_param);
1048 }
1049 }
1050
1051
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (GATE_FAILED(ret))
1052 {
1053 ret = gate_process_kill(&proc_handle);
1054 }
1055
1056
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (GATE_SUCCEEDED(ret) && (exit_code != NULL))
1057 {
1058 3 ret = gate_process_get_exitcode(&proc_handle, exit_code);
1059 }
1060 } while (0);
1061
1062
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (proc_handle)
1063 {
1064 3 gate_process_close(&proc_handle);
1065 }
1066
1067 7 return ret;
1068 }
1069
1070
1071 7 static gate_result_t run_generated_command(gate_string_t const* name,
1072 gate_service_message_callback_t msg_callback, void* user_param,
1073 gate_size_t(*cmd_generator)(gate_string_t const*, gate_string_t const*, gate_string_t*, gate_size_t))
1074 {
1075 gate_result_t ret;
1076 7 gate_string_t script_path = GATE_STRING_INIT_EMPTY;
1077 7 gate_string_t daemon_name = GATE_STRING_INIT_EMPTY;
1078 daemon_info_t daemon_info;
1079 gate_string_t args[16];
1080 gate_size_t ndx;
1081 7 gate_size_t args_used = 0;
1082 7 int script_exit_code = 0;
1083
1084 do
1085 {
1086 7 gate_mem_clear(args, sizeof(args));
1087 7 ret = posix_resolve_script(name, &script_path, &daemon_info);
1088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 GATE_BREAK_IF_FAILED(ret);
1089
1090 7 gate_string_create_static(&daemon_name, daemon_info.name);
1091 7 args_used = cmd_generator(&daemon_name, &script_path, args, sizeof(args) / sizeof(args[0]));
1092
1093 #if defined(GATE_DEBUG_MODE)
1094 7 GATE_DEBUG_TRACE("run generated command:");
1095
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7 times.
25 for(ndx = 0; ndx != args_used; ++ndx)
1096 {
1097 18 GATE_DEBUG_TRACE_MSG_VALUE(args[ndx].str, ndx);
1098 }
1099 #endif
1100 7 ret = run_process_with_output_callback(&args[0], &args[1], args_used - 1, msg_callback, user_param, &script_exit_code);
1101
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 GATE_BREAK_IF_FAILED(ret);
1102
1103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (script_exit_code != 0)
1104 {
1105 GATE_DEBUG_TRACE_MSG_VALUE("generated command execution failed: ", script_exit_code);
1106 ret = GATE_RESULT_EXECUTIONFAILED;
1107 }
1108 } while (0);
1109
1110 7 gate_string_release(&script_path);
1111
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7 times.
25 for (ndx = 0; ndx != args_used; ++ndx)
1112 {
1113 18 gate_string_release(&args[ndx]);
1114 }
1115 7 return ret;
1116 }
1117
1118 1 gate_result_t gate_service_start(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
1119 {
1120 1 return run_generated_command(name, msg_callback, user_param, &create_start_command_args);
1121 }
1122
1123 1 gate_result_t gate_service_stop(gate_string_t const* name, gate_uint32_t wait_timeout, gate_bool_t force,
1124 gate_service_message_callback_t msg_callback, void* user_param)
1125 {
1126 1 return run_generated_command(name, msg_callback, user_param, &create_stop_command_args);
1127 }
1128
1129 gate_result_t gate_service_get_config(gate_string_t const* name, gate_service_config_t* config)
1130 {
1131 return GATE_RESULT_NOTIMPLEMENTED;
1132 }
1133
1134 1 gate_result_t gate_service_get_status(gate_string_t const* name, gate_enumint_t* state, gate_string_t* process_id)
1135 {
1136 1 gate_result_t ret = run_generated_command(name, NULL, NULL, &create_status_command_args);
1137
1138
1/3
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
1 switch (ret)
1139 {
1140 1 case GATE_RESULT_OK:
1141 {
1142
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (state)
1143 {
1144 1 *state = GATE_SERVICE_STATE_RUNNING;
1145 }
1146
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (process_id)
1147 {
1148 1 gate_string_create_empty(process_id);
1149 }
1150 1 break;
1151 }
1152 case GATE_RESULT_EXECUTIONFAILED:
1153 {
1154 if (state)
1155 {
1156 *state = GATE_SERVICE_STATE_STOPPED;
1157 }
1158 if (process_id)
1159 {
1160 gate_string_create_empty(process_id);
1161 }
1162 ret = GATE_RESULT_OK;
1163 break;
1164 }
1165 default:
1166 {
1167 if (state)
1168 {
1169 *state = GATE_SERVICE_STATE_UNKNOWN;
1170 }
1171 break;
1172 }
1173 }
1174
1175 1 return ret;
1176 }
1177
1178
1179 #if defined(GATE_SYS_BSD)
1180
1181 #else /* defined(GATE_SYS_LINUX) */
1182
1183 #endif
1184
1185
1186 1 gate_result_t create_init_script_code(
1187 gate_string_t const* name, gate_string_t const* daemon_path, gate_string_t const* daemon_args,
1188 gate_string_t const* descr, gate_uint32_t flags, gate_string_t const* dependencies,
1189 gate_string_t* script_code)
1190 {
1191 1 gate_result_t ret = GATE_RESULT_FAILED;
1192 gate_size_t ndx;
1193 1 gate_strbuilder_t script_builder = GATE_INIT_EMPTY;
1194 char const* line;
1195 gate_size_t linelen;
1196 gate_string_t linesrc;
1197 gate_string_t expanded_line;
1198 1 var_mapping_t var_mapping[] = {
1199 { SCRIPT_VAR_NAME, name },
1200 { SCRIPT_VAR_DAEMON, daemon_path },
1201 { SCRIPT_VAR_ARGS, daemon_args },
1202 { SCRIPT_VAR_DESCR, descr }
1203 };
1204
1205 do
1206 {
1207 1 gate_strbuilder_create(&script_builder, 2048 + 1024);
1208
1209
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 1 times.
124 for (ndx = 0; ndx != posix_daemon_script_lines_count; ++ndx)
1210 {
1211 123 line = posix_daemon_script_lines[ndx];
1212 123 linelen = gate_str_length(line);
1213
1214 123 gate_string_create_static_len(&linesrc, line, linelen);
1215
1/2
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
123 if (NULL != expand_script_variables(&linesrc, var_mapping, sizeof(var_mapping) / sizeof(var_mapping[0]), &expanded_line))
1216 {
1217 123 gate_strbuilder_append_string(&script_builder, &expanded_line);
1218 123 gate_strbuilder_append_cstr(&script_builder, "\n");
1219 123 gate_string_release(&expanded_line);
1220 }
1221 }
1222
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_strbuilder_to_string(&script_builder, script_code))
1223 {
1224 ret = GATE_RESULT_OUTOFMEMORY;
1225 break;
1226 }
1227
1228 /* success case: */
1229 1 ret = GATE_RESULT_OK;
1230 } while (0);
1231
1232 1 gate_strbuilder_release(&script_builder);
1233 1 return ret;
1234 }
1235
1236 1 gate_result_t gate_service_register(gate_string_t const* name, gate_string_t const* command, gate_string_t const* descr,
1237 gate_uint32_t flags, gate_string_t const* dependencies,
1238 gate_service_message_callback_t msg_callback, void* user_param)
1239 {
1240 gate_result_t ret;
1241 1 gate_string_t daemon_path = GATE_STRING_INIT_EMPTY;
1242 1 gate_string_t daemon_args = GATE_STRING_INIT_EMPTY;
1243 1 gate_string_t script_code = GATE_STRING_INIT_EMPTY;
1244 1 gate_string_t updater_path = GATE_STRING_INIT_EMPTY;
1245 1 gate_string_t script_file_path = GATE_STRING_INIT_EMPTY;
1246 1 gate_filestream_t* ptr_filestrm = NULL;
1247 1 gate_size_t lenwritten = 0;
1248
1249
1250 do
1251 {
1252 static gate_enumint_t const script_file_flags = GATE_STREAM_OPEN_WRITE | GATE_FILE_OPEN_CREATEEXECUTABLE;
1253 /* TODO: split command into path + args */
1254 1 gate_string_duplicate(&daemon_path, command);
1255
1256 1 ret = create_init_script_code(name, &daemon_path, &daemon_args, descr, flags, dependencies, &script_code);
1257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1258
1259
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == posix_create_script_file_path(name, &script_file_path))
1260 {
1261 ret = GATE_RESULT_OUTOFMEMORY;
1262 break;
1263 }
1264
1265 1 ret = gate_file_openstream(&script_file_path, script_file_flags, &ptr_filestrm);
1266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1267 1 ret = gate_stream_write_block((gate_stream_t*)ptr_filestrm, gate_string_ptr(&script_code, 0), gate_string_length(&script_code), &lenwritten);
1268
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1269
1270 1 gate_object_release(ptr_filestrm);
1271 1 ptr_filestrm = NULL;
1272
1273 1 run_generated_command(name, msg_callback, user_param, &create_add_daemon_command_args);
1274 1 run_generated_command(name, msg_callback, user_param, &create_enable_daemon_command_args);
1275
1276 } while (0);
1277
1278 1 gate_string_release(&daemon_path);
1279 1 gate_string_release(&daemon_args);
1280 1 gate_string_release(&script_code);
1281 1 gate_string_release(&updater_path);
1282 1 gate_string_release(&script_file_path);
1283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ptr_filestrm)
1284 {
1285 gate_object_release(ptr_filestrm);
1286 }
1287 1 return ret;
1288 }
1289
1290 1 gate_result_t gate_service_unregister(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
1291 {
1292 1 gate_result_t ret = GATE_RESULT_FAILED;
1293 1 gate_string_t script_file_path = GATE_STRING_INIT_EMPTY;
1294
1295 do
1296 {
1297 1 run_generated_command(name, msg_callback, user_param, &create_disable_daemon_command_args);
1298 1 run_generated_command(name, msg_callback, user_param, &create_remove_daemon_command_args);
1299
1300
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == posix_create_script_file_path(name, &script_file_path))
1301 {
1302 ret = GATE_RESULT_OUTOFMEMORY;
1303 break;
1304 }
1305
1306
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (GATE_RESULT_OK == gate_file_exists(&script_file_path))
1307 {
1308 1 ret = gate_file_delete(&script_file_path);
1309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
1310 }
1311
1312 1 ret = GATE_RESULT_OK;
1313 } while (0);
1314
1315 1 gate_string_release(&script_file_path);
1316
1317 1 return ret;
1318 }
1319
1320 #endif /* GATE_SYSTEM_SERVICES_POSIX_IMPL */
1321