GCC Code Coverage Report


Directory: src/gate/
File: src/gate/system/services.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 331 0.0%
Functions: 0 26 0.0%
Branches: 0 180 0.0%

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
33 #if defined(GATE_SYS_WIN)
34 # if defined(GATE_SYS_WINCE)
35 # define GATE_SYSTEM_SERVICES_WINCE_IMPL
36 # elif defined(GATE_SYS_WINSTORE) || defined(GATE_SYS_WIN16)
37 # define GATE_SYSTEM_SERVICES_NO_IMPL
38 # else
39 # define GATE_SYSTEM_SERVICES_WIN32_IMPL
40 # endif
41 #elif defined(GATE_SYS_POSIX)
42 # define GATE_SYSTEM_SERVICES_POSIX_IMPL
43 #elif defined(GATE_SYS_EFI)
44 # define GATE_SYSTEM_SERVICES_NO_IMPL
45 #elif defined(GATE_SYS_DOS)
46 # define GATE_SYSTEM_SERVICES_NO_IMPL
47 #else
48 # define GATE_SYSTEM_SERVICES_NO_IMPL
49 #endif
50
51
52
53 /* generic implementation: */
54 char const* gate_service_print_state(gate_enumint_t state)
55 {
56 switch (state)
57 {
58 case GATE_SERVICE_STATE_STOPPED: return "Stopped";
59 case GATE_SERVICE_STATE_RUNNING: return "Running";
60 case GATE_SERVICE_STATE_ERROR: return "Error";
61 case GATE_SERVICE_STATE_PAUSED: return "Paused";
62 case GATE_SERVICE_STATE_STARTING: return "Starting";
63 case GATE_SERVICE_STATE_STOPPING: return "Stopping";
64 default:
65 case GATE_SERVICE_STATE_UNKNOWN: return "Unknown";
66 }
67 }
68
69
70
71 #if defined(GATE_SYSTEM_SERVICES_WINCE_IMPL)
72
73 gate_result_t gate_services_enum(gate_service_enum_callback_t callback, void* user_param)
74 {
75 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
76
77 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
78 return ret;
79 }
80
81 gate_result_t gate_service_start(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
82 {
83 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
84
85 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
86 return ret;
87 }
88
89 gate_result_t gate_service_stop(gate_string_t const* name, gate_uint32_t wait_timeout, gate_bool_t force,
90 gate_service_message_callback_t msg_callback, void* user_param)
91 {
92 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
93
94 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
95 return ret;
96 }
97
98 gate_result_t gate_service_get_config(gate_string_t const* name, gate_service_config_t* cfg)
99 {
100 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
101
102 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
103 return ret;
104 }
105
106 gate_result_t gate_service_get_status(gate_string_t const* name, gate_enumint_t* state, gate_string_t* process_id)
107 {
108 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
109
110 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
111 return ret;
112 }
113
114 gate_result_t gate_service_register(gate_string_t const* name, gate_string_t const* path, gate_string_t const* descr,
115 gate_uint32_t flags, gate_string_t const* dependencies,
116 gate_service_message_callback_t msg_callback, void* user_param)
117 {
118 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
119
120 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
121 return ret;
122 }
123
124 gate_result_t gate_service_unregister(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
125 {
126 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
127
128 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
129 return ret;
130 }
131
132 #endif /* GATE_SYSTEM_SERVICES_WINCE_IMPL */
133
134
135
136 #if defined(GATE_SYSTEM_SERVICES_WIN32_IMPL)
137
138 #include "gate/platforms.h"
139 #include "gate/platform/windows/win32registry.h"
140 #include "gate/processes.h"
141 #include "gate/applications.h"
142
143 #if defined(GATE_WIN32_ANSI)
144 # define GATE_SYSTEM_SERVICES_WIN9X_SUPPORT 1
145 #endif
146
147 typedef struct _GATE_SERVICE_STATUS_PROCESS
148 {
149 DWORD dwServiceType;
150 DWORD dwCurrentState;
151 DWORD dwControlsAccepted;
152 DWORD dwWin32ExitCode;
153 DWORD dwServiceSpecificExitCode;
154 DWORD dwCheckPoint;
155 DWORD dwWaitHint;
156 DWORD dwProcessId;
157 DWORD dwServiceFlags;
158 } GATE_SERVICE_STATUS_PROCESS;
159
160
161 typedef struct gate_win32_service_api_class
162 {
163
164 SC_HANDLE(WINAPI* AdvOpenSCManager)(LPCSTR lpMachineName, LPCSTR lpDatabaseName, DWORD dwDesiredAccess);
165 BOOL(WINAPI* AdvCloseServiceHandle)(SC_HANDLE hSCObject);
166 BOOL(WINAPI* AdvEnumServicesStatus)(SC_HANDLE hSCManager, DWORD dwServiceType, DWORD dwServiceState,
167 LPENUM_SERVICE_STATUS lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
168 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle);
169 SC_HANDLE(WINAPI* AdvOpenService)(SC_HANDLE hSCManager, LPCTSTR lpServiceName, DWORD dwDesiredAccess);
170 BOOL(WINAPI* AdvStartService)(SC_HANDLE hService, DWORD dwNumServiceArgs, LPCTSTR* lpServiceArgVectors);
171 BOOL(WINAPI* AdvControlService)(SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus);
172 BOOL(WINAPI* AdvQueryServiceConfig)(SC_HANDLE hService, LPQUERY_SERVICE_CONFIG lpServiceConfig, DWORD cbBufSize,
173 LPDWORD pcbBytesNeeded);
174 BOOL(WINAPI* AdvChangeServiceConfig)(SC_HANDLE hService, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl,
175 LPCTSTR lpBinaryPathName, LPCTSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCTSTR lpDependencies,
176 LPCTSTR lpServiceStartName, LPCTSTR lpPassword, LPCTSTR lpDisplayName);
177 BOOL(WINAPI* AdvQueryServiceStatus)(SC_HANDLE hService, LPSERVICE_STATUS lpServiceStatus);
178 BOOL(WINAPI* AdvQueryServiceStatusEx)(SC_HANDLE hService, GATE_SC_STATUS_TYPE InfoLevel, LPBYTE lpBuffer,
179 DWORD cbBufSize, LPDWORD pcbBytesNeeded);
180 SC_HANDLE(WINAPI* AdvCreateService)(SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPCTSTR lpDisplayName, DWORD dwDesiredAccess,
181 DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCTSTR lpBinaryPathName,
182 LPCTSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCTSTR lpDependencies,
183 LPCTSTR lpServiceStartName, LPCTSTR lpPassword);
184 BOOL(WINAPI* AdvDeleteService)(SC_HANDLE hService);
185 } gate_win32_service_api_t;
186
187 #define DUAL_NAME(name) GATE_WIN32_DUAL_NAME(name)
188
189 static gate_win32_service_api_t* win32_service_api()
190 {
191 static gate_win32_service_api_t service_api = GATE_INIT_EMPTY;
192 static gate_atomic_int_t service_api_load_state = 0;
193 gate_int32_t state;
194
195 do
196 {
197 state = gate_atomic_int_xchg_if(&service_api_load_state, 0, 1);
198 if (state >= 2)
199 {
200 break;
201 }
202 else if (state == 0)
203 {
204 /* load service _api */
205 HMODULE hadvapi = gate_win32_get_advapi_module();
206 if (hadvapi != NULL)
207 {
208 gate_win32_get_proc_address(hadvapi, DUAL_NAME("OpenSCManager"), &service_api.AdvOpenSCManager);
209 gate_win32_get_proc_address(hadvapi, "CloseServiceHandle", &service_api.AdvCloseServiceHandle);
210 gate_win32_get_proc_address(hadvapi, DUAL_NAME("EnumServicesStatus"), &service_api.AdvEnumServicesStatus);
211 gate_win32_get_proc_address(hadvapi, DUAL_NAME("OpenService"), &service_api.AdvOpenService);
212 gate_win32_get_proc_address(hadvapi, DUAL_NAME("StartService"), &service_api.AdvStartService);
213 gate_win32_get_proc_address(hadvapi, "ControlService", &service_api.AdvControlService);
214 gate_win32_get_proc_address(hadvapi, DUAL_NAME("QueryServiceConfig"), &service_api.AdvQueryServiceConfig);
215 gate_win32_get_proc_address(hadvapi, DUAL_NAME("ChangeServiceConfig"), &service_api.AdvChangeServiceConfig);
216 gate_win32_get_proc_address(hadvapi, "QueryServiceStatus", &service_api.AdvQueryServiceStatus);
217 gate_win32_get_proc_address(hadvapi, "QueryServiceStatusEx", &service_api.AdvQueryServiceStatusEx);
218 gate_win32_get_proc_address(hadvapi, DUAL_NAME("CreateService"), &service_api.AdvCreateService);
219 gate_win32_get_proc_address(hadvapi, "DeleteService", &service_api.AdvDeleteService);
220 }
221 gate_atomic_int_set(&service_api_load_state, 2);
222 break;
223 }
224 Sleep(0);
225
226 } while (state == 1);
227
228 return &service_api;
229 };
230
231
232
233
234
235
236
237 static BOOL query_service_status(SC_HANDLE h_service, GATE_SERVICE_STATUS_PROCESS* status)
238 {
239 DWORD bytes_needed = sizeof(GATE_SERVICE_STATUS_PROCESS);
240 gate_win32_service_api_t const* const api = win32_service_api();
241
242 if (api->AdvQueryServiceStatusEx)
243 {
244 return api->AdvQueryServiceStatusEx(h_service, GATE_SC_STATUS_PROCESS_INFO,
245 (LPBYTE)status, sizeof(GATE_SERVICE_STATUS_PROCESS), &bytes_needed);
246 }
247 else if (api->AdvQueryServiceStatus)
248 {
249 gate_mem_clear(status, sizeof(GATE_SERVICE_STATUS_PROCESS));
250 return api->AdvQueryServiceStatus(h_service, (SERVICE_STATUS*)status);
251 }
252 else
253 {
254 gate_win32_setlasterror(ERROR_CALL_NOT_IMPLEMENTED);
255 return FALSE;
256 }
257 }
258
259 static gate_bool_t close_sc_handle(SC_HANDLE handle)
260 {
261 gate_bool_t ret = false;
262 gate_win32_service_api_t const* const api = win32_service_api();
263
264 if (handle != NULL)
265 {
266 if (api->AdvCloseServiceHandle)
267 {
268 if (api->AdvCloseServiceHandle(handle))
269 {
270 ret = true;
271 }
272 }
273 }
274 else
275 {
276 ret = true;
277 }
278 return ret;
279 }
280
281 #ifndef SC_MANAGER_CONNECT
282 #define SC_MANAGER_CONNECT 0x0001
283 #endif
284 #ifndef SC_MANAGER_CREATE_SERVICE
285 #define SC_MANAGER_CREATE_SERVICE 0x0002
286 #endif
287 #ifndef SC_MANAGER_ENUMERATE_SERVICE
288 #define SC_MANAGER_ENUMERATE_SERVICE 0x0004
289 #endif
290 #ifndef SC_MANAGER_LOCK
291 #define SC_MANAGER_LOCK 0x0008
292 #endif
293 #ifndef SC_MANAGER_QUERY_LOCK_STATUS
294 #define SC_MANAGER_QUERY_LOCK_STATUS 0x0010
295 #endif
296 #ifndef SC_MANAGER_MODIFY_BOOT_CONFIG
297 #define SC_MANAGER_MODIFY_BOOT_CONFIG 0x0020
298 #endif
299
300 #ifndef SERVICE_ACTIVE
301 #define SERVICE_ACTIVE 0x00000001
302 #endif
303 #ifndef SERVICE_INACTIVE
304 #define SERVICE_INACTIVE 0x00000002
305 #endif
306 #ifndef SERVICE_STATE_ALL
307 #define SERVICE_STATE_ALL (SERVICE_ACTIVE | SERVICE_INACTIVE)
308 #endif
309
310
311 #ifndef SERVICE_START
312 #define SERVICE_START 0x0010
313 #endif
314 #ifndef SERVICE_STOP
315 #define SERVICE_STOP 0x0020
316 #endif
317
318 #ifndef SERVICE_STOPPED
319 #define SERVICE_STOPPED 0x00000001
320 #endif
321 #ifndef SERVICE_START_PENDING
322 #define SERVICE_START_PENDING 0x00000002
323 #endif
324 #ifndef SERVICE_STOP_PENDING
325 #define SERVICE_STOP_PENDING 0x00000003
326 #endif
327 #ifndef SERVICE_RUNNING
328 #define SERVICE_RUNNING 0x00000004
329 #endif
330 #ifndef SERVICE_CONTINUE_PENDING
331 #define SERVICE_CONTINUE_PENDING 0x00000005
332 #endif
333 #ifndef SERVICE_PAUSE_PENDING
334 #define SERVICE_PAUSE_PENDING 0x00000006
335 #endif
336 #ifndef SERVICE_PAUSED
337 #define SERVICE_PAUSED 0x00000007
338 #endif
339
340 #ifndef SERVICE_CONTROL_STOP
341 #define SERVICE_CONTROL_STOP 0x00000001
342 #endif
343
344 #ifndef SERVICE_QUERY_CONFIG
345 #define SERVICE_QUERY_CONFIG 0x0001
346 #endif
347 #ifndef SERVICE_CHANGE_CONFIG
348 #define SERVICE_CHANGE_CONFIG 0x0002
349 #endif
350 #ifndef SERVICE_QUERY_STATUS
351 #define SERVICE_QUERY_STATUS 0x0004
352 #endif
353 #ifndef SERVICE_ENUMERATE_DEPENDENTS
354 #define SERVICE_ENUMERATE_DEPENDENTS 0x0008
355 #endif
356 #ifndef SERVICE_START
357 #define SERVICE_START 0x0010
358 #endif
359 #ifndef SERVICE_STOP
360 #define SERVICE_STOP 0x0020
361 #endif
362 #ifndef SERVICE_PAUSE_CONTINUE
363 #define SERVICE_PAUSE_CONTINUE 0x0040
364 #endif
365 #ifndef SERVICE_INTERROGATE
366 #define SERVICE_INTERROGATE 0x0080
367 #endif
368 #ifndef SERVICE_USER_DEFINED_CONTROL
369 #define SERVICE_USER_DEFINED_CONTROL 0x0100
370 #endif
371
372 #ifndef SERVICE_ALL_ACCESS
373 #define SERVICE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \
374 SERVICE_QUERY_CONFIG | \
375 SERVICE_CHANGE_CONFIG | \
376 SERVICE_QUERY_STATUS | \
377 SERVICE_ENUMERATE_DEPENDENTS | \
378 SERVICE_START | \
379 SERVICE_STOP | \
380 SERVICE_PAUSE_CONTINUE | \
381 SERVICE_INTERROGATE | \
382 SERVICE_USER_DEFINED_CONTROL)
383 #endif
384
385 static gate_result_t gate_service_enum_nt(gate_service_enum_callback_t callback, void* user_param)
386 {
387 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
388 SC_HANDLE sc_handle = NULL;
389 char buffer[4096];
390 gate_win32_service_api_t const* const api = win32_service_api();
391
392 do
393 {
394 gate_bool_t continue_enum = true;
395 DWORD dwResumeHandle = 0;
396 gate_mem_clear(buffer, sizeof(buffer));
397
398 sc_handle = api->AdvOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
399 if (NULL == sc_handle)
400 {
401 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenSCManager");
402 gate_win32_print_lasterror(&ret, NULL, 0);
403 break;
404 }
405
406 ret = GATE_RESULT_OK;
407 while (continue_enum)
408 {
409 LPENUM_SERVICE_STATUS ptr_service_status = (LPENUM_SERVICE_STATUS)&buffer[0];
410 LPENUM_SERVICE_STATUS ptr_status;
411 DWORD dwBytesNeeded;
412 DWORD dwServicesReturned;
413 DWORD dwIndex;
414
415 if (api->AdvEnumServicesStatus(sc_handle, SERVICE_WIN32, SERVICE_STATE_ALL, ptr_service_status, sizeof(buffer),
416 &dwBytesNeeded, &dwServicesReturned, &dwResumeHandle))
417 {
418 continue_enum = false;
419 }
420 else
421 {
422 if (ERROR_MORE_DATA != gate_win32_getlasterror())
423 {
424 gate_win32_print_lasterror(&ret, NULL, 0);
425 break;
426 }
427 }
428
429 for (dwIndex = 0; dwIndex != dwServicesReturned; ++dwIndex)
430 {
431 gate_service_t service;
432 gate_mem_clear(&service, sizeof(service));
433 ptr_status = &ptr_service_status[dwIndex];
434
435 gate_win32_winstr_2_utf8(
436 ptr_status->lpServiceName, gate_win32_winstr_length(ptr_status->lpServiceName),
437 service.name, sizeof(service.name));
438
439 gate_win32_winstr_2_utf8(
440 ptr_status->lpDisplayName, gate_win32_winstr_length(ptr_status->lpDisplayName),
441 service.description, sizeof(service.description));
442
443 if (callback)
444 {
445 if (!callback(&service, user_param))
446 {
447 /* cancel further enumeration */
448 continue_enum = false;
449 break;
450 }
451 }
452 }
453 }
454 } while (0);
455
456 close_sc_handle(sc_handle);
457
458 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
459 return ret;
460 }
461
462 #if defined(GATE_SYSTEM_SERVICES_WIN9X_SUPPORT)
463 static TCHAR const win9x_runservices[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices");
464
465 struct enum_9x_param
466 {
467 gate_service_enum_callback_t cb;
468 void* user_param;
469 };
470 static gate_bool_t enum_9x_reg_callback(LPCTSTR key_path, LPCTSTR value_name,
471 gate_enumint_t value_type, gate_size_t value_size, void* userparam)
472 {
473 struct enum_9x_param* ptr_param = (struct enum_9x_param*)userparam;
474 gate_bool_t ret = false;
475 gate_service_t service;
476 gate_size_t value_name_len;
477
478 gate_mem_clear(&service, sizeof(service));
479 value_name_len = gate_win32_str_len(value_name);
480 gate_win32_winstr_2_utf8(value_name, value_name_len, service.name, sizeof(service.name) - 1);
481 service.flags = 0;
482
483 if (ptr_param->cb)
484 {
485 ret = ptr_param->cb(&service, ptr_param->user_param);
486 }
487 return ret;
488 }
489
490 static gate_result_t gate_service_enum_9x(gate_service_enum_callback_t callback, void* user_param)
491 {
492 struct enum_9x_param param;
493 param.cb = callback;
494 param.user_param = user_param;
495 return gate_win32_registry_enum_values(GATE_WIN32_REGISTRY_LOCALMACHINE, win9x_runservices, &enum_9x_reg_callback, (void*)&param);
496 }
497
498 static gate_string_t* gate_service_get_9x_path(gate_string_t const* service_name, gate_string_t* service_path)
499 {
500 TCHAR tsvc_name[256];
501 gate_result_t result;
502
503 gate_win32_utf8_2_winstr(gate_string_ptr(service_name, 0), gate_string_length(service_name), tsvc_name, sizeof(tsvc_name) / sizeof(tsvc_name[0]) - 1);
504 result = gate_win32_registry_read_string(GATE_WIN32_REGISTRY_LOCALMACHINE, win9x_runservices, tsvc_name, service_path);
505 if (GATE_SUCCEEDED(result))
506 {
507 return service_path;
508 }
509 return NULL;
510 }
511
512 struct service_processes_param
513 {
514 gate_string_t const* service_path;
515 gate_process_id_t pid;
516 gate_bool_t found;
517 };
518
519 static gate_bool_t service_processes_callback(gate_process_t* process, void* userparam)
520 {
521 struct service_processes_param* ptr_param = (struct service_processes_param*)userparam;
522 if (gate_string_equals_str_ic(ptr_param->service_path, process->path))
523 {
524 ptr_param->pid = process->pid;
525 ptr_param->found = true;
526 return false;
527 }
528 return true;
529 }
530
531 static gate_result_t gate_service_get_9x_pid(gate_string_t const* service_name, gate_string_t const* service_path, gate_process_id_t* ptr_pid)
532 {
533 gate_result_t ret = GATE_RESULT_FAILED;
534 struct service_processes_param param;
535
536 do
537 {
538 param.service_path = service_path;
539 param.pid = 0;
540 param.found = false;
541 ret = gate_process_enum(&service_processes_callback, (void*)&param, GATE_PROCESS_ENUM_PATH);
542 GATE_BREAK_IF_FAILED(ret);
543 if (!param.found)
544 {
545 ret = GATE_RESULT_NOMATCH;
546 break;
547 }
548
549 if (ptr_pid)
550 {
551 *ptr_pid = param.pid;
552 }
553 ret = GATE_RESULT_OK;
554 } while (0);
555 return ret;
556 }
557
558 #endif
559
560
561
562 gate_result_t gate_services_enum(gate_service_enum_callback_t callback, void* user_param)
563 {
564 gate_win32_service_api_t const* const api = win32_service_api();
565
566 #if defined(GATE_SYSTEM_SERVICES_WIN9X_SUPPORT)
567 if (!gate_win32_is_winnt4_or_newer())
568 {
569 /* assume 9x */
570 return gate_service_enum_9x(callback, user_param);
571 }
572 #endif
573 if (api->AdvOpenSCManager && api->AdvEnumServicesStatus)
574 {
575 return gate_service_enum_nt(callback, user_param);
576 }
577 return GATE_RESULT_NOTIMPLEMENTED;
578 }
579
580 gate_result_t gate_service_start(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
581 {
582 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
583 SC_HANDLE sc_handle = NULL;
584 SC_HANDLE h_service = NULL;
585 TCHAR svc_name[256];
586 gate_win32_service_api_t const* const api = win32_service_api();
587
588 GATE_UNUSED_ARG(msg_callback);
589 GATE_UNUSED_ARG(user_param);
590
591 #if defined(GATE_SYSTEM_SERVICES_WIN9X_SUPPORT)
592 if (!gate_win32_is_winnt4_or_newer())
593 {
594 /* Win9x fallback */
595 gate_string_t svc_path = GATE_STRING_INIT_EMPTY;
596 gate_string_t svc_args[64];
597 gate_size_t arg_count = 0;
598 gate_size_t ndx;
599
600 ret = GATE_RESULT_FAILED;
601 gate_mem_clear(&svc_args[0], sizeof(svc_args));
602
603 if (gate_service_get_9x_path(name, &svc_path))
604 {
605 arg_count = gate_app_parse_args(&svc_path, &svc_args[0], sizeof(svc_args) / sizeof(svc_args[0]));
606 if (arg_count > 0)
607 {
608 ret = gate_process_start(&svc_args[0], &svc_args[1], arg_count - 1, NULL, NULL, 0, 0, NULL, NULL, NULL);
609 }
610 else
611 {
612 ret = GATE_RESULT_INVALIDDATA;
613 }
614 }
615 else
616 {
617 ret = GATE_RESULT_NOTAVAILABLE;
618 }
619
620 for (ndx = 0; ndx != arg_count; ++ndx)
621 {
622 gate_string_release(&svc_args[ndx]);
623 }
624 gate_string_release(&svc_path);
625 }
626 else
627 #endif
628 if (api->AdvOpenSCManager)
629 {
630 do
631 {
632 gate_win32_utf8_2_winstr(name->str, name->length, &svc_name[0], sizeof(svc_name) / sizeof(svc_name[0]));
633
634 sc_handle = api->AdvOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
635 if (NULL == sc_handle)
636 {
637 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenSCManager");
638 gate_win32_print_lasterror(&ret, NULL, 0);
639 break;
640 }
641 h_service = api->AdvOpenService(sc_handle, svc_name, SERVICE_START);
642 if (NULL == h_service)
643 {
644 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenService");
645 gate_win32_print_lasterror(&ret, NULL, 0);
646 break;
647 }
648 if (!api->AdvStartService(h_service, 0, NULL))
649 {
650 GATE_DEBUG_TRACE_PLATFORM_ERROR("StartService");
651 gate_win32_print_lasterror(&ret, NULL, 0);
652 }
653 else
654 {
655 ret = GATE_RESULT_OK;
656 }
657 } while (0);
658
659 close_sc_handle(h_service);
660 close_sc_handle(sc_handle);
661 }
662 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
663 return ret;
664 }
665
666 gate_result_t gate_service_stop(gate_string_t const* name, gate_uint32_t wait_timeout_ms, gate_bool_t force,
667 gate_service_message_callback_t msg_callback, void* user_param)
668 {
669 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
670 SC_HANDLE sc_handle = NULL;
671 SC_HANDLE h_service = NULL;
672 TCHAR svc_name[256];
673 SERVICE_STATUS service_status = GATE_INIT_EMPTY;
674 GATE_SERVICE_STATUS_PROCESS service_status_process = GATE_INIT_EMPTY;
675 HANDLE h_proc = NULL;
676 DWORD bytes_needed;
677 ULONGLONG timer_started;
678 DWORD delay = 0;
679 gate_win32_service_api_t const* const api = win32_service_api();
680
681 GATE_UNUSED_ARG(msg_callback);
682 GATE_UNUSED_ARG(user_param);
683
684 #if defined(GATE_SYSTEM_SERVICES_WIN9X_SUPPORT)
685 if (!gate_win32_is_winnt4_or_newer())
686 {
687 /* Win9x fallback */
688 gate_string_t svc_path = GATE_STRING_INIT_EMPTY;
689 gate_string_t svc_args[2];
690 gate_size_t arg_count = 0;
691 gate_size_t ndx;
692 gate_process_id_t pid = 0;
693
694 ret = GATE_RESULT_FAILED;
695 gate_mem_clear(&svc_args[0], sizeof(svc_args));
696
697 do
698 {
699 if (!gate_service_get_9x_path(name, &svc_path))
700 {
701 ret = GATE_RESULT_NOTAVAILABLE;
702 break;
703 }
704 arg_count = gate_app_parse_args(&svc_path, &svc_args[0], sizeof(svc_args) / sizeof(svc_args[0]));
705 if (arg_count == 0)
706 {
707 ret = GATE_RESULT_NOTAVAILABLE;
708 break;
709 }
710 ret = gate_service_get_9x_pid(name, &svc_args[0], &pid);
711 GATE_BREAK_IF_FAILED(ret);
712
713 h_proc = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, (DWORD)pid);
714 ret = gate_process_terminate_pid(pid, true);
715 if (h_proc == NULL)
716 {
717 break;
718 }
719 if ((wait_timeout_ms > 0) || force)
720 {
721 if (WAIT_OBJECT_0 == WaitForSingleObject(h_proc, (DWORD)wait_timeout_ms))
722 {
723 ret = GATE_RESULT_OK;
724 }
725 else
726 {
727 if (force)
728 {
729 ret = TerminateProcess(h_proc, 666) ? GATE_RESULT_OK : GATE_RESULT_FAILED;
730 }
731 else
732 {
733 ret = GATE_RESULT_TIMEOUT;
734 }
735 }
736 CloseHandle(h_proc);
737 }
738 } while (0);
739
740 for (ndx = 0; ndx != arg_count; ++ndx)
741 {
742 gate_string_release(&svc_args[ndx]);
743 }
744 gate_string_release(&svc_path);
745 }
746 else
747 #endif
748 if (api->AdvOpenSCManager)
749 {
750 do
751 {
752 gate_win32_utf8_2_winstr(name->str, name->length, &svc_name[0], sizeof(svc_name) / sizeof(svc_name[0]));
753
754 sc_handle = api->AdvOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
755 if (NULL == sc_handle)
756 {
757 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenSCManager");
758 gate_win32_print_lasterror(&ret, NULL, 0);
759 break;
760 }
761 h_service = api->AdvOpenService(sc_handle, svc_name, SERVICE_STOP | SERVICE_QUERY_STATUS);
762 if (NULL == h_service)
763 {
764 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenService");
765 gate_win32_print_lasterror(&ret, NULL, 0);
766 break;
767 }
768
769 bytes_needed = sizeof(service_status_process);
770 if (query_service_status(h_service, &service_status_process))
771 {
772 if (service_status_process.dwCurrentState == SERVICE_STOPPED)
773 {
774 /* service is already stopped -> nothing to do -> success */
775 ret = GATE_RESULT_OK;
776 break;
777 }
778 if (service_status_process.dwProcessId != 0)
779 {
780 h_proc = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, service_status_process.dwProcessId);
781 }
782 }
783
784 if (!api->AdvControlService(h_service, SERVICE_CONTROL_STOP, &service_status))
785 {
786 GATE_DEBUG_TRACE_PLATFORM_ERROR("ControlService");
787 gate_win32_print_lasterror(&ret, NULL, 0);
788 break;
789 }
790 /* service has received shutdown request */
791 ret = GATE_RESULT_OK;
792
793 if ((wait_timeout_ms > 0) || force)
794 {
795 /* await shutdown */
796 if (h_proc != NULL)
797 {
798 switch (WaitForSingleObject(h_proc, wait_timeout_ms))
799 {
800 case WAIT_OBJECT_0:
801 {
802 ret = GATE_RESULT_OK;
803 break;
804 }
805 case WAIT_TIMEOUT:
806 {
807 if (force)
808 {
809 /* service did not respond within timeout -> kill it*/
810 if (!TerminateProcess(h_proc, 666))
811 {
812 ret = GATE_RESULT_EXECUTIONFAILED;
813 }
814 else
815 {
816 ret = GATE_RESULT_OK;
817 }
818 }
819 else
820 {
821 ret = GATE_RESULT_TIMEOUT;
822 }
823 break;
824 }
825 default:
826 {
827 ret = GATE_RESULT_EXECUTIONINTERRUPTED;
828 break;
829 }
830 }
831 }
832 else /* (h_proc != NULL) */
833 {
834 /* no process handle to synchronize with, try to await by polling */
835
836 ret = GATE_RESULT_TIMEOUT; /* assume we will run into a timeout if no other state becomes available */
837 delay = 1;
838 timer_started = gate_win32_get_tick_count();
839 while (gate_win32_get_tick_count() - timer_started <= (gate_uint64_t)wait_timeout_ms)
840 {
841 bytes_needed = sizeof(service_status_process);
842
843 if (!query_service_status(h_service, &service_status_process))
844 {
845 /* cannot retrieve status -> synchronization failed */
846 ret = GATE_RESULT_NOTREADY;
847 break;
848 }
849 else
850 {
851 if (service_status_process.dwCurrentState == SERVICE_STOPPED)
852 {
853 ret = GATE_RESULT_OK;
854 break;
855 }
856 }
857 Sleep(delay); /* wait until next status poll */
858 if (delay < 250)
859 {
860 ++delay;
861 }
862 }
863 if (force && (ret == GATE_RESULT_TIMEOUT))
864 {
865 /* we cannot enforce process shutdown after shutdown -> return specific error */
866 ret = GATE_RESULT_EXECUTIONFAILED;
867 }
868
869 } /* (h_proc != NULL) */
870 }
871 } while (0);
872
873 if (h_proc != NULL)
874 {
875 CloseHandle(h_proc);
876 }
877
878 close_sc_handle(h_service);
879 close_sc_handle(sc_handle);
880 }
881 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
882 return ret;
883 }
884
885 gate_result_t gate_service_get_config(gate_string_t const* name, gate_service_config_t* config)
886 {
887 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
888 gate_win32_service_api_t const* const api = win32_service_api();
889
890 #if defined(GATE_SYSTEM_SERVICES_WIN9X_SUPPORT)
891 if (!gate_win32_is_winnt4_or_newer())
892 {
893 /* Win9x fallback */
894 gate_string_t svc_path = GATE_STRING_INIT_EMPTY;
895 gate_size_t arg_count = 0;
896
897 if (gate_service_get_9x_path(name, &svc_path))
898 {
899 gate_mem_clear(config, sizeof(gate_service_config_t));
900 gate_string_to_buffer(name, config->name, sizeof(config->name) / sizeof(config->name[0]));
901 gate_string_to_buffer(&svc_path, config->command, sizeof(config->command) / sizeof(config->command[0]));
902 config->flags = GATE_SERVICE_STATE_UNKNOWN;
903 ret = GATE_RESULT_OK;
904 }
905 else
906 {
907 ret = GATE_RESULT_NOTAVAILABLE;
908 }
909 gate_string_release(&svc_path);
910 }
911 else
912 #endif
913 if (api->AdvOpenSCManager)
914 {
915 SC_HANDLE sc_handle = NULL;
916 SC_HANDLE h_service = NULL;
917 DWORD bytes_needed = 0;
918 LPCTSTR ptr_dependency;
919 gate_size_t length_dependency;
920 gate_strbuilder_t dependency_builder;
921 gate_size_t dep_buffer_used;
922 char buffer[8192];
923 TCHAR svc_name[256];
924 char dep_buffer[256];
925
926 gate_mem_clear(buffer, sizeof(buffer));
927 gate_mem_clear(svc_name, sizeof(svc_name));
928 gate_mem_clear(dep_buffer, sizeof(dep_buffer));
929
930 do
931 {
932 LPQUERY_SERVICE_CONFIG ptr_config = (LPQUERY_SERVICE_CONFIG)&buffer[0];
933 gate_win32_utf8_2_winstr(name->str, name->length, &svc_name[0], sizeof(svc_name) / sizeof(svc_name[0]));
934
935 sc_handle = api->AdvOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
936 if (NULL == sc_handle)
937 {
938 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenSCManager");
939 gate_win32_print_lasterror(&ret, NULL, 0);
940 break;
941 }
942 h_service = api->AdvOpenService(sc_handle, svc_name, SERVICE_QUERY_CONFIG);
943 if (NULL == h_service)
944 {
945 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenService");
946 gate_win32_print_lasterror(&ret, NULL, 0);
947 break;
948 }
949 if (!api->AdvQueryServiceConfig(h_service, ptr_config, sizeof(buffer), &bytes_needed))
950 {
951 GATE_DEBUG_TRACE_PLATFORM_ERROR("QueryServiceConfig");
952 gate_win32_print_lasterror(&ret, NULL, 0);
953 break;
954 }
955
956 if (config)
957 {
958 gate_mem_clear(config, sizeof(gate_service_config_t));
959
960 gate_str_print_text(config->name, sizeof(config->name), name->str, name->length);
961
962 gate_win32_winstr_2_utf8(ptr_config->lpDisplayName, gate_win32_winstr_length(ptr_config->lpDisplayName),
963 config->description, sizeof(config->description));
964
965 gate_win32_winstr_2_utf8(ptr_config->lpBinaryPathName, gate_win32_winstr_length(ptr_config->lpBinaryPathName),
966 config->command, sizeof(config->command));
967
968 ptr_dependency = ptr_config->lpDependencies;
969 if (ptr_dependency)
970 {
971 gate_strbuilder_create_static(&dependency_builder, config->dependencies, sizeof(config->dependencies), 0);
972 while (0 != (length_dependency = gate_win32_winstr_length(ptr_dependency)))
973 {
974 if (gate_strbuilder_length(&dependency_builder) > 0)
975 {
976 gate_strbuilder_append_text(&dependency_builder, ",", 1);
977 }
978 dep_buffer_used = gate_win32_winstr_2_utf8(ptr_dependency, length_dependency, dep_buffer, sizeof(dep_buffer));
979 gate_strbuilder_append_text(&dependency_builder, dep_buffer, dep_buffer_used);
980
981 ptr_dependency += length_dependency + 1;
982 }
983 }
984
985 config->flags = 0;
986 switch (ptr_config->dwStartType)
987 {
988 case GATE_SERVICE_FLAG_AUTOSTART: config->flags = GATE_SERVICE_FLAG_AUTOSTART; break;
989 case GATE_SERVICE_FLAG_DISABLED: config->flags = GATE_SERVICE_FLAG_DISABLED; break;
990 default: break;
991 }
992
993 }
994 ret = GATE_RESULT_OK;
995 } while (0);
996
997 close_sc_handle(h_service);
998 close_sc_handle(sc_handle);
999 }
1000 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
1001 return ret;
1002 }
1003
1004 gate_result_t gate_service_get_status(gate_string_t const* name, gate_enumint_t* state, gate_string_t* process_id)
1005 {
1006 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1007 SC_HANDLE sc_handle = NULL;
1008 SC_HANDLE h_service = NULL;
1009 TCHAR svc_name[256];
1010 GATE_SERVICE_STATUS_PROCESS status = GATE_INIT_EMPTY;
1011 DWORD bytes_needed;
1012 char pid_buffer[32] = GATE_INIT_EMPTY;
1013 gate_size_t pid_used = 0;
1014 gate_win32_service_api_t const* const api = win32_service_api();
1015
1016 #if defined(GATE_SYSTEM_SERVICES_WIN9X_SUPPORT)
1017 if (!gate_win32_is_winnt4_or_newer())
1018 {
1019 /* Win9x fallback */
1020 gate_string_t svc_path = GATE_STRING_INIT_EMPTY;
1021 gate_string_t svc_args[2];
1022 gate_size_t arg_count = 0;
1023 gate_size_t ndx;
1024 gate_process_id_t pid = 0;
1025 char pid_buffer[256];
1026 gate_size_t pid_buffer_used;
1027
1028 ret = GATE_RESULT_FAILED;
1029 gate_mem_clear(&svc_args[0], sizeof(svc_args));
1030
1031 if (gate_service_get_9x_path(name, &svc_path))
1032 {
1033 arg_count = gate_app_parse_args(&svc_path, &svc_args[0], sizeof(svc_args) / sizeof(svc_args[0]));
1034 if (arg_count > 0)
1035 {
1036 ret = gate_service_get_9x_pid(name, &svc_args[0], &pid);
1037 if (GATE_SUCCEEDED(ret))
1038 {
1039 if (state)
1040 {
1041 *state = GATE_SERVICE_STATE_RUNNING;
1042 }
1043 if (process_id)
1044 {
1045 pid_buffer_used = gate_process_print_pid(pid, pid_buffer, sizeof(pid_buffer) - 1);
1046 gate_string_create(process_id, pid_buffer, pid_buffer_used);
1047 }
1048 }
1049 else
1050 {
1051 if (state)
1052 {
1053 *state = GATE_SERVICE_STATE_STOPPED;
1054 }
1055 }
1056 ret = GATE_RESULT_OK;
1057 }
1058 else
1059 {
1060 ret = GATE_RESULT_INVALIDDATA;
1061 }
1062 }
1063 else
1064 {
1065 ret = GATE_RESULT_NOTAVAILABLE;
1066 }
1067
1068 for (ndx = 0; ndx != arg_count; ++ndx)
1069 {
1070 gate_string_release(&svc_args[ndx]);
1071 }
1072 gate_string_release(&svc_path);
1073 }
1074 else
1075 #endif
1076 if (api->AdvOpenSCManager)
1077 {
1078 do
1079 {
1080 gate_win32_utf8_2_winstr(name->str, name->length, &svc_name[0], sizeof(svc_name) / sizeof(svc_name[0]));
1081
1082 sc_handle = api->AdvOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
1083 if (NULL == sc_handle)
1084 {
1085 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenSCManager");
1086 gate_win32_print_lasterror(&ret, NULL, 0);
1087 break;
1088 }
1089 h_service = api->AdvOpenService(sc_handle, svc_name, SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS);
1090 if (NULL == h_service)
1091 {
1092 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenService");
1093 gate_win32_print_lasterror(&ret, NULL, 0);
1094 break;
1095 }
1096 bytes_needed = sizeof(status);
1097 if (!query_service_status(h_service, &status))
1098 {
1099 GATE_DEBUG_TRACE_PLATFORM_ERROR("QueryServiceStatusEx");
1100 gate_win32_print_lasterror(&ret, NULL, 0);
1101 break;
1102 }
1103
1104 /* success case: */
1105 if (state)
1106 {
1107 switch (status.dwCurrentState)
1108 {
1109 case SERVICE_STOPPED: *state = GATE_SERVICE_STATE_STOPPED; break;
1110 case SERVICE_START_PENDING: *state = GATE_SERVICE_STATE_STARTING; break;
1111 case SERVICE_STOP_PENDING: *state = GATE_SERVICE_STATE_STOPPING; break;
1112 case SERVICE_RUNNING: *state = GATE_SERVICE_STATE_RUNNING; break;
1113 case SERVICE_CONTINUE_PENDING: *state = GATE_SERVICE_STATE_PAUSED; break;
1114 case SERVICE_PAUSE_PENDING: *state = GATE_SERVICE_STATE_PAUSED; break;
1115 case SERVICE_PAUSED: *state = GATE_SERVICE_STATE_PAUSED; break;
1116 default: *state = GATE_SERVICE_STATE_UNKNOWN; break;
1117 }
1118 }
1119 if (process_id)
1120 {
1121 gate_string_create_empty(process_id);
1122 pid_used = gate_str_print_uint(pid_buffer, sizeof(pid_buffer), status.dwProcessId, 0);
1123 gate_string_create(process_id, pid_buffer, pid_used);
1124 }
1125 ret = GATE_RESULT_OK;
1126 } while (0);
1127
1128 close_sc_handle(h_service);
1129 close_sc_handle(sc_handle);
1130 }
1131 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
1132 return ret;
1133 }
1134
1135 gate_result_t gate_service_register(gate_string_t const* name, gate_string_t const* path, gate_string_t const* descr,
1136 gate_uint32_t flags, gate_string_t const* dependencies,
1137 gate_service_message_callback_t msg_callback, void* user_param)
1138 {
1139 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1140 SC_HANDLE sc_handle = NULL;
1141 SC_HANDLE h_service = NULL;
1142 TCHAR svc_name[256] = GATE_INIT_EMPTY;
1143 TCHAR svc_descr[256] = GATE_INIT_EMPTY;
1144 TCHAR svc_path[GATE_MAX_FILEPATH_LENGTH] = GATE_INIT_EMPTY;
1145 TCHAR svc_dep[2048 + 1024] = GATE_INIT_EMPTY;
1146 DWORD dwType = 0, dwStart = 0, dwError = 0;
1147 char const* ptr_dep;
1148 gate_size_t dep_len;
1149 gate_size_t dep_pos1, dep_pos2;
1150 gate_bool_t continue_dep = true;
1151 TCHAR* ptr_svc_dep = &svc_dep[0];
1152 gate_size_t svc_dep_len = sizeof(svc_dep) / sizeof(svc_dep[0]) - 2;
1153 gate_size_t svc_dep_used;
1154 gate_win32_service_api_t const* const api = win32_service_api();
1155
1156
1157 GATE_UNUSED_ARG(msg_callback);
1158 GATE_UNUSED_ARG(user_param);
1159
1160 gate_win32_utf8_2_winstr(name->str, name->length, &svc_name[0], sizeof(svc_name) / sizeof(svc_name[0]));
1161
1162 #if defined(GATE_SYSTEM_SERVICES_WIN9X_SUPPORT)
1163 if (!gate_win32_is_winnt4_or_newer())
1164 {
1165 /* Win9x fallback*/
1166 gate_win32_registry_create_path(GATE_WIN32_REGISTRY_LOCALMACHINE, win9x_runservices);
1167 ret = gate_win32_registry_write_str(GATE_WIN32_REGISTRY_LOCALMACHINE, win9x_runservices,
1168 svc_name, gate_string_ptr(path, 0), gate_string_length(path));
1169 /* NOTICE: OpenSCManager does exist on Win9x to cooperate with NT4 */
1170 }
1171 else
1172 #endif
1173 if (api->AdvOpenSCManager)
1174 {
1175 do
1176 {
1177 gate_win32_utf8_2_winstr(path->str, path->length, &svc_path[0], sizeof(svc_path) / sizeof(svc_path[0]));
1178 if (descr)
1179 {
1180 gate_win32_utf8_2_winstr(descr->str, descr->length, &svc_descr[0], sizeof(svc_descr) / sizeof(svc_descr[0]));
1181 }
1182
1183 if (!gate_string_is_empty(dependencies))
1184 {
1185 dep_pos1 = 0;
1186 ptr_dep = dependencies->str;
1187 dep_len = dependencies->length;
1188 while (continue_dep && svc_dep_len != 0)
1189 {
1190 dep_pos2 = gate_str_char_pos(ptr_dep, dep_len, ',', dep_pos1);
1191 if (dep_pos2 == GATE_STR_NPOS)
1192 {
1193 continue_dep = false;
1194 dep_pos2 = dep_len;
1195 }
1196 svc_dep_used = gate_win32_utf8_2_winstr(&ptr_dep[dep_pos1], dep_pos2 - dep_pos1, ptr_svc_dep, svc_dep_len);
1197
1198 dep_pos1 = dep_pos2 + 1;
1199 ptr_svc_dep += svc_dep_used;
1200 svc_dep_len -= svc_dep_used;
1201 *ptr_svc_dep = 0;
1202 ++ptr_svc_dep;
1203 --svc_dep_len;
1204
1205 }
1206 *ptr_svc_dep = 0;
1207 ++ptr_svc_dep;
1208 --svc_dep_len;
1209 }
1210
1211 sc_handle = api->AdvOpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
1212 if (NULL == sc_handle)
1213 {
1214 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenSCManager");
1215 gate_win32_print_lasterror(&ret, NULL, 0);
1216 break;
1217 }
1218
1219 dwType = SERVICE_WIN32_OWN_PROCESS;
1220 dwStart = 0;
1221 if (GATE_FLAG_ENABLED(flags, GATE_SERVICE_FLAG_AUTOSTART))
1222 {
1223 dwStart = SERVICE_AUTO_START;
1224 }
1225 else if (GATE_FLAG_ENABLED(flags, GATE_SERVICE_FLAG_DISABLED))
1226 {
1227 dwStart = SERVICE_DISABLED;
1228 }
1229 else
1230 {
1231 dwStart = SERVICE_DEMAND_START;
1232 }
1233 dwError = SERVICE_ERROR_NORMAL;
1234 h_service = api->AdvCreateService(sc_handle, svc_name, svc_descr, SERVICE_ALL_ACCESS,
1235 dwType, dwStart, dwError, svc_path,
1236 NULL, NULL, svc_dep, NULL, NULL);
1237 if (h_service == NULL)
1238 {
1239 GATE_DEBUG_TRACE_PLATFORM_ERROR("CreateService");
1240 gate_win32_print_lasterror(&ret, NULL, 0);
1241 }
1242 else
1243 {
1244 ret = GATE_RESULT_OK;
1245 }
1246 } while (0);
1247
1248 close_sc_handle(h_service);
1249 close_sc_handle(sc_handle);
1250 }
1251 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
1252 return ret;
1253 }
1254
1255 gate_result_t gate_service_unregister(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
1256 {
1257 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1258 SC_HANDLE sc_handle = NULL;
1259 SC_HANDLE h_service = NULL;
1260 TCHAR tsvc_name[1024];
1261 gate_win32_service_api_t const* const api = win32_service_api();
1262
1263 GATE_UNUSED_ARG(msg_callback);
1264 GATE_UNUSED_ARG(user_param);
1265
1266 gate_win32_utf8_2_winstr(name->str, name->length, &tsvc_name[0], sizeof(tsvc_name) / sizeof(tsvc_name[0]));
1267
1268 #if defined(GATE_SYSTEM_SERVICES_WIN9X_SUPPORT)
1269 if (!gate_win32_is_winnt4_or_newer())
1270 {
1271 /* Win9x fallback*/
1272 ret = gate_win32_registry_delete_value(GATE_WIN32_REGISTRY_LOCALMACHINE, win9x_runservices, tsvc_name);
1273 }
1274 else
1275 #endif
1276 if (api->AdvOpenSCManager)
1277 {
1278 do
1279 {
1280
1281 sc_handle = api->AdvOpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE | SC_MANAGER_CONNECT);
1282 if (NULL == sc_handle)
1283 {
1284 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenSCManager");
1285 gate_win32_print_lasterror(&ret, NULL, 0);
1286 break;
1287 }
1288 h_service = api->AdvOpenService(sc_handle, tsvc_name, DELETE);
1289 if (NULL == h_service)
1290 {
1291 GATE_DEBUG_TRACE_PLATFORM_ERROR("OpenService");
1292 gate_win32_print_lasterror(&ret, NULL, 0);
1293 break;
1294 }
1295 if (!api->AdvDeleteService(h_service))
1296 {
1297 GATE_DEBUG_TRACE_PLATFORM_ERROR("DeleteService");
1298 gate_win32_print_lasterror(&ret, NULL, 0);
1299 }
1300 else
1301 {
1302 ret = GATE_RESULT_OK;
1303 }
1304 } while (0);
1305
1306 close_sc_handle(h_service);
1307 close_sc_handle(sc_handle);
1308 }
1309 GATE_DEBUG_TRACE_FAILED_RESULT(ret);
1310 return ret;
1311 }
1312
1313 #endif /* GATE_SYSTEM_SERVICES_WIN32_IMPL */
1314
1315
1316
1317 #if defined(GATE_SYSTEM_SERVICES_POSIX_IMPL)
1318
1319 #include "gate/streams.h"
1320 #include "gate/files.h"
1321 #include "gate/platforms.h"
1322 #include "gate/processes.h"
1323 #include "gate/strings.h"
1324 #include "gate/debugging.h"
1325
1326 #define SCRIPT_VAR_SCRIPT "${GATE_SCRIPT_PATH}" /* init script path */
1327 #define SCRIPT_VAR_NAME "${GATE_DAEMON_NAME}" /* name of daemon/service */
1328 #define SCRIPT_VAR_DAEMON "${GATE_DAEMON_BIN}" /* path of daemon/service executable binary */
1329 #define SCRIPT_VAR_ARGS "${GATE_DAEMON_ARGS}" /* arguments of daemon/service process */
1330 #define SCRIPT_VAR_DESCR "${GATE_DAEMON_DESCR}" /* description text of daemon/service */
1331 #define SCRIPT_VAR_REQUIRE "${GATE_DAEMON_REQUIRE}" /* names of services requires */
1332
1333 typedef struct daemon_info_class
1334 {
1335 char name[128];
1336 char description[256];
1337 char dependencies[128 + 512];
1338 char daemon_path[512];
1339 char daemon_args[512];
1340 char pid_file[512];
1341 } daemon_info_t;
1342
1343
1344 #if defined(GATE_SYS_BSD)
1345
1346 #if defined(GATE_SYS_OPENBSD)
1347 /* OpenBSD */
1348 #define RCCTL_PATH "/usr/sbin/rcctl"
1349 static char const* bsd_daemon_start[] = { RCCTL_PATH, "start", SCRIPT_VAR_NAME };
1350 static char const* bsd_daemon_stop[] = { RCCTL_PATH, "stop", SCRIPT_VAR_NAME };
1351 static char const* bsd_daemon_status[] = { RCCTL_PATH, "check", SCRIPT_VAR_NAME };
1352 static char const* bsd_daemon_add[] = { "true" };
1353 static char const* bsd_daemon_enable[] = { RCCTL_PATH, "enable", SCRIPT_VAR_NAME };
1354 static char const* bsd_daemon_disable[] = { RCCTL_PATH, "disable", SCRIPT_VAR_NAME };
1355 static char const* bsd_daemon_remove[] = { "true" };
1356
1357 #elif defined(GATE_SYS_NETBSD)
1358
1359 /* NetBSD */
1360 static char const* bsd_daemon_start[] = { SCRIPT_VAR_SCRIPT, "start" };
1361 static char const* bsd_daemon_stop[] = { SCRIPT_VAR_SCRIPT, "stop" };
1362 static char const* bsd_daemon_status[] = { SCRIPT_VAR_SCRIPT, "status" };
1363 static char const* bsd_daemon_add[] = { "true" };
1364 static char const* bsd_daemon_enable[] = { "true" };
1365 static char const* bsd_daemon_disable[] = { "true" };
1366 static char const* bsd_daemon_remove[] = { "true" };
1367
1368 #else
1369
1370 /* FreeBSD */
1371 #define SERVICE_PATH "/usr/sbin/rcctl"
1372 static char const* bsd_daemon_start[] = { SERVICE_PATH, "start", SCRIPT_VAR_NAME };
1373 static char const* bsd_daemon_stop[] = { SERVICE_PATH, "stop", SCRIPT_VAR_NAME };
1374 static char const* bsd_daemon_status[] = { SERVICE_PATH, "status", SCRIPT_VAR_NAME };
1375 static char const* bsd_daemon_add[] = { "true" };
1376 static char const* bsd_daemon_enable[] = { "true" };
1377 static char const* bsd_daemon_disable[] = { "true" };
1378 static char const* bsd_daemon_remove[] = { "true" };
1379
1380 #endif
1381
1382 static char const* bsd_daemon_script_paths[] = { "/etc/rc.d/", "/usr/local/etc/rc.d/" };
1383
1384 #define posix_cmd_daemon_start bsd_daemon_start
1385 #define posix_cmd_daemon_start_count (sizeof(bsd_daemon_start) / sizeof(bsd_daemon_start[0]))
1386 #define posix_cmd_daemon_stop bsd_daemon_stop
1387 #define posix_cmd_daemon_stop_count (sizeof(bsd_daemon_stop) / sizeof(bsd_daemon_stop[0]))
1388 #define posix_cmd_daemon_status bsd_daemon_status
1389 #define posix_cmd_daemon_status_count (sizeof(bsd_daemon_status) / sizeof(bsd_daemon_status[0]))
1390 #define posix_cmd_daemon_add bsd_daemon_add
1391 #define posix_cmd_daemon_add_count (sizeof(bsd_daemon_add) / sizeof(bsd_daemon_add[0]))
1392 #define posix_cmd_daemon_enable bsd_daemon_enable
1393 #define posix_cmd_daemon_enable_count (sizeof(bsd_daemon_enable) / sizeof(bsd_daemon_enable[0]))
1394 #define posix_cmd_daemon_disable bsd_daemon_disable
1395 #define posix_cmd_daemon_disable_count (sizeof(bsd_daemon_disable) / sizeof(bsd_daemon_disable[0]))
1396 #define posix_cmd_daemon_remove bsd_daemon_remove
1397 #define posix_cmd_daemon_remove_count (sizeof(bsd_daemon_remove) / sizeof(bsd_daemon_remove[0]))
1398
1399 #define posix_init_script_paths bsd_daemon_script_paths
1400 #define posix_init_script_paths_count (sizeof(bsd_daemon_script_paths) / sizeof(bsd_daemon_script_paths[0]))
1401
1402 typedef struct bsd_script_info_class
1403 {
1404 char name[128];
1405 char descr[128];
1406 char require[256];
1407 char command[256];
1408 char command_args[256];
1409 char pid_file[256];
1410 } bsd_script_info_t;
1411
1412
1413 /* static gate_string_t const bsd_provides_token = GATE_STRING_INIT_STATIC("# PROVIDE:"); */
1414
1415 static gate_string_t const bsd_require_token = GATE_STRING_INIT_STATIC("# REQUIRE:");
1416 static gate_string_t const bsd_name_token = GATE_STRING_INIT_STATIC("name=");
1417 static gate_string_t const bsd_desc_token = GATE_STRING_INIT_STATIC("desc=");
1418
1419 #if defined(GATE_SYS_OPENBSD)
1420 static gate_string_t const bsd_command_token = GATE_STRING_INIT_STATIC("daemon=");
1421 static gate_string_t const bsd_command_args_token = GATE_STRING_INIT_STATIC("daemon_flags=");
1422 #else
1423 static gate_string_t const bsd_command_token = GATE_STRING_INIT_STATIC("command=");
1424 static gate_string_t const bsd_command_args_token = GATE_STRING_INIT_STATIC("command_args=");
1425 #endif
1426 static gate_string_t const bsd_pidfile_token = GATE_STRING_INIT_STATIC("pidfile=");
1427
1428 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)
1429 {
1430 if (gate_string_starts_with(line, start_token))
1431 {
1432 gate_str_print_text(dest_buffer, dest_buffer_len, &line->str[start_token->length], line->length - start_token->length);
1433 }
1434 }
1435
1436 static void optimize_extracted_field(char* ptr, gate_size_t capacity)
1437 {
1438 static char const trimmable[] = " \"\t";
1439 static gate_size_t const trimmable_count = 3;
1440 gate_size_t length = gate_str_length_max(ptr, capacity);
1441 gate_size_t pos;
1442
1443 pos = gate_str_find_first_not_of(ptr, length, &trimmable[0], trimmable_count, 0);
1444 if (pos == GATE_STR_NPOS)
1445 {
1446 ptr[0] = 0;
1447 return;
1448 }
1449 else if (pos > 0)
1450 {
1451 //abc45678
1452 length -= pos;
1453 gate_mem_move(&ptr[0], &ptr[pos], length);
1454 ptr[length] = 0;
1455 }
1456
1457 pos = gate_str_find_last_not_of(ptr, length, &trimmable[0], trimmable_count);
1458 if (pos != GATE_STR_NPOS)
1459 {
1460 ptr[pos + 1] = 0;
1461 }
1462 }
1463
1464 static gate_result_t get_bsd_script_info(gate_string_t const* script_file_path, bsd_script_info_t* ptr_info)
1465 {
1466 gate_result_t ret = GATE_RESULT_FAILED;
1467 gate_filestream_t* fs = NULL;
1468 char line_buffer[GATE_MAX_COPYBUFFER_LENGTH];
1469 gate_size_t line_len;
1470 gate_string_t line;
1471
1472 do
1473 {
1474 gate_mem_clear(ptr_info, sizeof(bsd_script_info_t));
1475 ret = gate_file_openstream(script_file_path, GATE_STREAM_OPEN_READ, &fs);
1476 GATE_BREAK_IF_FAILED(ret);
1477
1478 for (;;)
1479 {
1480 gate_mem_clear(line_buffer, sizeof(line_buffer));
1481 ret = gate_stream_read_line((gate_stream_t*)fs, line_buffer, sizeof(line_buffer), &line_len);
1482 GATE_BREAK_IF_FAILED(ret);
1483 if (line_len == 0)
1484 {
1485 break;
1486 }
1487 gate_string_create_static_len(&line, line_buffer, line_len);
1488 gate_string_trim(&line, &line);
1489
1490 extract_line_data_on_match(&line, &bsd_require_token, ptr_info->require, sizeof(ptr_info->require));
1491 extract_line_data_on_match(&line, &bsd_name_token, ptr_info->name, sizeof(ptr_info->name));
1492 extract_line_data_on_match(&line, &bsd_desc_token, ptr_info->descr, sizeof(ptr_info->descr));
1493 extract_line_data_on_match(&line, &bsd_command_token, ptr_info->command, sizeof(ptr_info->command));
1494 extract_line_data_on_match(&line, &bsd_command_args_token, ptr_info->command_args, sizeof(ptr_info->command_args));
1495 extract_line_data_on_match(&line, &bsd_pidfile_token, ptr_info->pid_file, sizeof(ptr_info->pid_file));
1496 }
1497
1498 if (gate_str_length(ptr_info->name) == 0)
1499 {
1500 gate_file_extract_path(script_file_path->str, script_file_path->length,
1501 ptr_info->name, sizeof(ptr_info->name),
1502 NULL, 0);
1503 }
1504 optimize_extracted_field(ptr_info->require, sizeof(ptr_info->require));
1505 optimize_extracted_field(ptr_info->name, sizeof(ptr_info->name));
1506 optimize_extracted_field(ptr_info->descr, sizeof(ptr_info->descr));
1507 optimize_extracted_field(ptr_info->command, sizeof(ptr_info->command));
1508 optimize_extracted_field(ptr_info->command_args, sizeof(ptr_info->command_args));
1509 optimize_extracted_field(ptr_info->pid_file, sizeof(ptr_info->pid_file));
1510 } while (0);
1511
1512 if (fs)
1513 {
1514 gate_object_release(fs);
1515 }
1516 return ret;
1517 }
1518
1519 static gate_result_t extract_daemon_script_info(gate_string_t const* script_file_path, daemon_info_t* info)
1520 {
1521 gate_result_t ret;
1522 bsd_script_info_t script_info;
1523
1524 do
1525 {
1526 gate_mem_clear(info, sizeof(daemon_info_t));
1527 ret = get_bsd_script_info(script_file_path, &script_info);
1528 GATE_BREAK_IF_FAILED(ret);
1529
1530 gate_str_print_text(info->name, sizeof(info->name), script_info.name, gate_str_length(script_info.name));
1531 gate_str_print_text(info->description, sizeof(info->description), script_info.descr, gate_str_length(script_info.descr));
1532 gate_str_print_text(info->daemon_path, sizeof(info->daemon_path), script_info.command, gate_str_length(script_info.command));
1533 gate_str_print_text(info->daemon_args, sizeof(info->daemon_args), script_info.command_args, gate_str_length(script_info.command_args));
1534 gate_str_print_text(info->dependencies, sizeof(info->dependencies), script_info.require, gate_str_length(script_info.require));
1535 gate_str_print_text(info->pid_file, sizeof(info->pid_file), script_info.pid_file, gate_str_length(script_info.pid_file));
1536
1537 /*
1538 //netbsd + freebsd:
1539 "# PROVIDE: abcd";
1540 "# REQUIRE: xyz";
1541 "name=\"abcd\"";
1542 "desc=\"abc daemon\"";
1543 "command=\"/usr/bin/${name}\"";
1544 "command_args=\"-x -y\"";
1545 "pidfile=\"/var/run/${name}.pid\"";
1546
1547 //openbsd
1548 "daemon=\"";
1549 "daemon_flags=\"";
1550 "daemon_use=\"";
1551 //ret = parse_bsd_init_script_file((gate_stream_t*)ptr_stream, &script_info);
1552 //GATE_BREAK_IF_FAILED(ret);
1553 */
1554 } while (0);
1555 return ret;
1556 }
1557
1558 static char const* bsd_init_script_lines[] = {
1559 "#!/bin/sh",
1560 "#",
1561 "#",
1562 "",
1563 "# PROVIDE: " SCRIPT_VAR_NAME,
1564 "# REQUIRE: " SCRIPT_VAR_REQUIRE,
1565 "",
1566 "# OpenGATE.at simple init script for: " SCRIPT_VAR_NAME,
1567 #if defined(GATE_SYS_OPENBSD)
1568 "daemon=\"" SCRIPT_VAR_DAEMON "\"",
1569 "daemon_flags=\"" SCRIPT_VAR_ARGS "\"",
1570 #else
1571 "command=\"" SCRIPT_VAR_DAEMON "\"",
1572 "command_args=\"" SCRIPT_VAR_ARGS "\"",
1573 #endif
1574 "name=\"" SCRIPT_VAR_NAME "\"",
1575 "desc=\"" SCRIPT_VAR_DESCR "\"",
1576 "pidfile=\"/var/run/" SCRIPT_VAR_NAME ".pid\"",
1577 "",
1578 "gate_daemon_start() {",
1579 #if defined(GATE_SYS_OPENBSD)
1580 " ${daemon} ${daemon_flags}",
1581 #else
1582 " ${command} ${command_args}",
1583 #endif
1584 "}",
1585 "gate_daemon_check() {",
1586 " if [ -f ${pidfile} ]; then",
1587 " read PID <${pidfile}",
1588 " if ps -p ${PID} > /dev/null 2>&1; then",
1589 " echo \"${name} is running\"",
1590 " return 0",
1591 " fi",
1592 " fi",
1593 " echo \"${name} is NOT running\"",
1594 " return 1",
1595 "}",
1596 "gate_daemon_stop() {",
1597 " if [ -f ${pidfile} ]; then",
1598 " read PID <${pidfile}",
1599 " rm -f ${pidfile}",
1600 " if ps -p ${PID} > /dev/null 2>&1; then",
1601 " kill -s TERM ${PID}",
1602 " echo \"Stop request sent\"",
1603 " return 0",
1604 " fi",
1605 " fi",
1606 " echo \"Stop request NOT performed\"",
1607 " return 1",
1608 "}",
1609 "",
1610 #if defined(GATE_SYS_OPENBSD)
1611 ". /etc/rc.d/rc.subr",
1612 "rc_start() {",
1613 " gate_daemon_start",
1614 " return",
1615 "}",
1616 "rc_check() {",
1617 " gate_daemon_check",
1618 " return",
1619 "}",
1620 "rc_stop() {",
1621 " gate_daemon_stop",
1622 " return",
1623 "}",
1624 "rc_cmd $1",
1625 #elif defined(GATE_SYS_NETBSD)
1626 "$_rc_subr_loaded . /etc/rc.subr",
1627 "start_cmd=\"gate_daemon_start\"",
1628 "stop_cmd=\"gate_daemon_stop\"",
1629 "load_rc_config $name",
1630 "run_rc_command \"$1\"",
1631 #else
1632 ". /etc/rc.subr",
1633 "start_cmd=\"gate_daemon_start\"",
1634 "stop_cmd=\"gate_daemon_stop\"",
1635 "load_rc_config $name",
1636 "run_rc_command \"$1\"",
1637 #endif
1638 ""
1639 };
1640
1641 #define posix_daemon_script_lines bsd_init_script_lines
1642 #define posix_daemon_script_lines_count (sizeof(bsd_init_script_lines) / sizeof(bsd_init_script_lines[0]))
1643
1644 #else
1645
1646 /* LINUX */
1647
1648 static char const* linux_init_start[] = { SCRIPT_VAR_SCRIPT, "start" };
1649 static char const* linux_init_stop[] = { SCRIPT_VAR_SCRIPT, "stop" };
1650 static char const* linux_init_status[] = { SCRIPT_VAR_SCRIPT, "status" };
1651 static char const* linux_init_add_daemon[] = { "/sbin/update-rc.d", SCRIPT_VAR_NAME, "defaults" };
1652 static char const* linux_init_enable_daemon[] = { "/sbin/update-rc.d", SCRIPT_VAR_NAME, "enable" };
1653 static char const* linux_init_disable_daemon[] = { "/sbin/update-rc.d", SCRIPT_VAR_NAME, "disable" };
1654 static char const* linux_init_remove_daemon[] = { "/sbin/update-rc.d", SCRIPT_VAR_NAME, "remove" };
1655
1656 static char const* linux_init_script_paths[] = { "/etc/init.d/" };
1657
1658 #define posix_cmd_daemon_start linux_init_start
1659 #define posix_cmd_daemon_start_count (sizeof(linux_init_start) / sizeof(linux_init_start[0]))
1660 #define posix_cmd_daemon_stop linux_init_stop
1661 #define posix_cmd_daemon_stop_count (sizeof(linux_init_stop) / sizeof(linux_init_stop[0]))
1662 #define posix_cmd_daemon_status linux_init_status
1663 #define posix_cmd_daemon_status_count (sizeof(linux_init_status) / sizeof(linux_init_status[0]))
1664 #define posix_cmd_daemon_add linux_init_add_daemon
1665 #define posix_cmd_daemon_add_count (sizeof(linux_init_add_daemon) / sizeof(linux_init_add_daemon[0]))
1666 #define posix_cmd_daemon_enable linux_init_enable_daemon
1667 #define posix_cmd_daemon_enable_count (sizeof(linux_init_enable_daemon) / sizeof(linux_init_enable_daemon[0]))
1668 #define posix_cmd_daemon_disable linux_init_disable_daemon
1669 #define posix_cmd_daemon_disable_count (sizeof(linux_init_disable_daemon) / sizeof(linux_init_disable_daemon[0]))
1670 #define posix_cmd_daemon_remove linux_init_remove_daemon
1671 #define posix_cmd_daemon_remove_count (sizeof(linux_init_remove_daemon) / sizeof(linux_init_remove_daemon[0]))
1672 #define posix_init_script_paths linux_init_script_paths
1673 #define posix_init_script_paths_count (sizeof(linux_init_script_paths) / sizeof(linux_init_script_paths[0]))
1674
1675
1676
1677 static char const* linux_systemd_start[] = { "systemctl", "start", SCRIPT_VAR_NAME };
1678 static char const* linux_systemd_stop[] = { "systemctl", "stop", SCRIPT_VAR_NAME };
1679 static char const* linux_systemd_status[] = { "systemctl", "status", SCRIPT_VAR_NAME };
1680
1681
1682 static gate_string_t const token_begin_init_info = GATE_STRING_INIT_STATIC("### BEGIN INIT INFO");
1683 static gate_string_t const token_end_init_info = GATE_STRING_INIT_STATIC("### END INIT INFO");
1684
1685 static gate_string_t const token_hashtag = GATE_STRING_INIT_STATIC("#");
1686
1687 static gate_string_t const token_init_info_provides = GATE_STRING_INIT_STATIC("Provides");
1688 static gate_string_t const token_init_info_req_start = GATE_STRING_INIT_STATIC("Required-Start");
1689 static gate_string_t const token_init_info_req_stop = GATE_STRING_INIT_STATIC("Required-Stop");
1690 static gate_string_t const token_init_info_def_start = GATE_STRING_INIT_STATIC("Default-Start");
1691 static gate_string_t const token_init_info_def_stop = GATE_STRING_INIT_STATIC("Default-Stop");
1692 static gate_string_t const token_init_info_short_descr = GATE_STRING_INIT_STATIC("Short-Description");
1693 static gate_string_t const token_init_info_description = GATE_STRING_INIT_STATIC("Description");
1694 static gate_string_t const token_init_info_daemon_path = GATE_STRING_INIT_STATIC("Daemon-Path");
1695 static gate_string_t const token_init_info_pid_file = GATE_STRING_INIT_STATIC("Pid-File");
1696
1697 static gate_string_t const token_var_daemon = GATE_STRING_INIT_STATIC("DAEMON=");
1698 /* static gate_string_t const token_var_agent = GATE_STRING_INIT_STATIC("AGENT="); */
1699 /* static gate_string_t const token_var_pidfile = GATE_STRING_INIT_STATIC("PIDFILE="); */
1700
1701
1702 typedef struct linux_init_script_info_class
1703 {
1704 char provides[128];
1705 char default_start[64];
1706 char default_stop[64];
1707 char required_start[256];
1708 char required_stop[256];
1709 char short_description[256];
1710 char description[256];
1711 char daemon_path[256];
1712 char pid_file[256];
1713 } linux_init_script_info_t;
1714
1715 static gate_result_t parse_linux_init_script_file(gate_stream_t* stream, linux_init_script_info_t* info)
1716 {
1717 gate_result_t ret = GATE_RESULT_OK;
1718 char line_buffer[1024];
1719 gate_size_t received;
1720 gate_string_t str_line;
1721 gate_bool_t in_init_header = false;
1722 gate_bool_t init_header_completed = false;
1723 gate_string_t str_key;
1724 gate_string_t str_value;
1725 gate_size_t pos;
1726
1727 gate_mem_clear(info, sizeof(linux_init_script_info_t));
1728
1729 while (GATE_SUCCEEDED(ret))
1730 {
1731 ret = gate_stream_read_line(stream, line_buffer, sizeof(line_buffer), &received);
1732 GATE_BREAK_IF_FAILED(ret);
1733 if (received == 0)
1734 {
1735 break;
1736 }
1737 gate_string_create_static_len(&str_line, line_buffer, received);
1738 gate_string_trim(&str_line, &str_line);
1739 if (gate_string_is_empty(&str_line))
1740 {
1741 continue; /* skip empty lines */
1742 }
1743
1744 if (!init_header_completed)
1745 {
1746 if (!in_init_header)
1747 {
1748 if (gate_string_starts_with(&str_line, &token_begin_init_info))
1749 {
1750 in_init_header = true;
1751 }
1752 else
1753 {
1754 continue;
1755 }
1756 }
1757 else
1758 {
1759 if (gate_string_starts_with(&str_line, &token_end_init_info))
1760 {
1761 init_header_completed = true;
1762 }
1763 else if (gate_string_starts_with(&str_line, &token_hashtag))
1764 {
1765 /* parse init script header entries */
1766 pos = gate_string_char_pos(&str_line, ':', 1);
1767 if (pos == GATE_STR_NPOS)
1768 {
1769 continue;
1770 }
1771 gate_string_substr(&str_key, &str_line, 1, pos - 1);
1772 gate_string_substr(&str_value, &str_line, pos + 1, GATE_STR_NPOS);
1773 gate_string_trim(&str_key, &str_key);
1774 gate_string_trim(&str_value, &str_value);
1775 if (gate_string_starts_with(&str_key, &token_init_info_provides)) GATE_STRING_TO_BUFFER(&str_value, info->provides);
1776 else if (gate_string_starts_with(&str_key, &token_init_info_req_start)) GATE_STRING_TO_BUFFER(&str_value, info->required_start);
1777 else if (gate_string_starts_with(&str_key, &token_init_info_req_stop)) GATE_STRING_TO_BUFFER(&str_value, info->required_stop);
1778 else if (gate_string_starts_with(&str_key, &token_init_info_def_start)) GATE_STRING_TO_BUFFER(&str_value, info->default_start);
1779 else if (gate_string_starts_with(&str_key, &token_init_info_def_stop)) GATE_STRING_TO_BUFFER(&str_value, info->default_stop);
1780 else if (gate_string_starts_with(&str_key, &token_init_info_short_descr)) GATE_STRING_TO_BUFFER(&str_value, info->short_description);
1781 else if (gate_string_starts_with(&str_key, &token_init_info_description)) GATE_STRING_TO_BUFFER(&str_value, info->description);
1782 else if (gate_string_starts_with(&str_key, &token_init_info_daemon_path)) GATE_STRING_TO_BUFFER(&str_value, info->daemon_path);
1783 else if (gate_string_starts_with(&str_key, &token_init_info_pid_file)) GATE_STRING_TO_BUFFER(&str_value, info->pid_file);
1784 else continue;
1785 }
1786 else
1787 {
1788 continue;
1789 }
1790 }
1791 } /*if(!init_header_completed)*/
1792 else
1793 {
1794 if (gate_str_is_empty(info->daemon_path))
1795 {
1796 if (gate_string_starts_with(&str_line, &token_var_daemon))
1797 {
1798 gate_string_substr(&str_value, &str_line, token_var_daemon.length, GATE_STR_NPOS);
1799 gate_string_trim(&str_value, &str_value);
1800 GATE_STRING_TO_BUFFER(&str_value, info->daemon_path);
1801 }
1802 else if (gate_string_starts_with(&str_line, &token_var_daemon))
1803 {
1804 gate_string_substr(&str_value, &str_line, token_var_daemon.length, GATE_STR_NPOS);
1805 gate_string_trim(&str_value, &str_value);
1806 GATE_STRING_TO_BUFFER(&str_value, info->daemon_path);
1807 }
1808 }
1809 if (gate_str_is_empty(info->pid_file))
1810 {
1811 gate_string_substr(&str_value, &str_line, token_var_daemon.length, GATE_STR_NPOS);
1812 gate_string_trim(&str_value, &str_value);
1813 if (str_value.length > 2)
1814 {
1815 if ((str_value.str[0] == '\"') && (str_value.str[str_value.length - 1] == '\"'))
1816 {
1817 ++str_value.str;
1818 str_value.length -= 2;
1819 }
1820 }
1821 GATE_STRING_TO_BUFFER(&str_value, info->pid_file);
1822 }
1823 }
1824 }
1825 return ret;
1826 }
1827
1828 static gate_result_t extract_daemon_script_info(gate_string_t const* script_file_path, daemon_info_t* info)
1829 {
1830 gate_result_t ret;
1831 gate_filestream_t* ptr_stream = NULL;
1832 linux_init_script_info_t script_info;
1833 do
1834 {
1835 gate_mem_clear(&script_info, sizeof(script_info));
1836 ret = gate_file_openstream(script_file_path, GATE_STREAM_OPEN_READ, &ptr_stream);
1837 GATE_BREAK_IF_FAILED(ret);
1838
1839 ret = parse_linux_init_script_file((gate_stream_t*)ptr_stream, &script_info);
1840 GATE_BREAK_IF_FAILED(ret);
1841
1842 gate_str_print_text(info->name, sizeof(info->name), script_info.provides, gate_str_length(script_info.provides));
1843 gate_str_print_text(info->description, sizeof(info->description), script_info.description, gate_str_length(script_info.description));
1844 gate_str_print_text(info->daemon_path, sizeof(info->daemon_path), script_info.daemon_path, gate_str_length(script_info.daemon_path));
1845 gate_str_print_text(info->pid_file, sizeof(info->pid_file), script_info.pid_file, gate_str_length(script_info.pid_file));
1846 gate_str_print_text(info->dependencies, sizeof(info->dependencies), script_info.required_start, gate_str_length(script_info.required_start));
1847 } while (0);
1848 if (ptr_stream)
1849 {
1850 gate_object_release(ptr_stream);
1851 }
1852 return ret;
1853 }
1854
1855 static char const* linux_init_script_lines[] = {
1856 "#! /bin/sh",
1857 "### BEGIN INIT INFO",
1858 "# Provides: " SCRIPT_VAR_NAME,
1859 "# Required-Start: $remote_fs $syslog",
1860 "# Required-Stop: $remote_fs $syslog",
1861 "# Default-Start: 2 3 4 5",
1862 "# Default-Stop: 0 1 6",
1863 "# Short-Description: " SCRIPT_VAR_DESCR,
1864 "# Description: " SCRIPT_VAR_DESCR,
1865 "### END INIT INFO",
1866 "",
1867 "# Author: OpenGATE Framework",
1868 "#",
1869 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
1870 "NAME=\"" SCRIPT_VAR_NAME "\"",
1871 "DAEMON=\"" SCRIPT_VAR_DAEMON "\"",
1872 "DAEMON_ARGS=\"" SCRIPT_VAR_ARGS "\"",
1873 "PIDFILE=\"/var/run/$NAME.pid\"",
1874 "TMPPIDFILE=\"/tmp/$NAME.pid\"",
1875 "SCRIPTNAME=\"/etc/init.d/$NAME\"",
1876 "export SYSTEMD_NO_WRAP=1",
1877 "export SYSTEMCTL_SKIP_REDIRECT=1",
1878 "",
1879 "[ -x \"$DAEMON\" ] || exit 0",
1880 "[ -r /etc/default/$NAME ] && . /etc/default/$NAME",
1881 "[ -r /lib/init/vars.sh ] && . /lib/init/vars.sh",
1882 "[ -r /lib/lsb/init-functions ] && . /lib/lsb/init-functions",
1883 "[ -r /etc/init.d/functions ] && . /etc/init.d/functions",
1884 "",
1885 "is_pid_running() {",
1886 " if ps -p $1 > /dev/null 2>&1; then",
1887 " return 0",
1888 " else",
1889 " return 1",
1890 " fi;",
1891 "}",
1892 "",
1893 "do_stop() {",
1894 " if [ -f $PIDFILE ]; then",
1895 " read PID <$PIDFILE",
1896 " fi",
1897 " rm -f $PIDFILE",
1898 " if [ -z \"$PID\" ]; then",
1899 " return 0",
1900 " fi",
1901 " if is_pid_running $PID; then",
1902 " echo \"Stopping $NAME (PID $PID).\"",
1903 " kill -s TERM $PID",
1904 " else",
1905 " echo \"$NAME (PID $PID) stopped.\"",
1906 " return 0",
1907 " fi",
1908 " COUNTER=0",
1909 " while [ $COUNTER -lt 50 ]; do",
1910 " if is_pid_running $PID;",
1911 " then",
1912 " sleep 0.1",
1913 " COUNTER=$((COUNTER+1))",
1914 " else",
1915 " COUNTER=$((COUNTER+50))",
1916 " fi",
1917 " done",
1918 " if is_pid_running $PID; then",
1919 " echo \"Killing $NAME (PID $PID).\"",
1920 " kill -s KILL $PID",
1921 " fi",
1922 " echo \"$NAME (PID $PID) stopped.\"",
1923 " return 0",
1924 "}",
1925 "",
1926 "do_start() {",
1927 " $DAEMON $DAEMON_ARGS &>/dev/null",
1928 " exit 0",
1929 "}",
1930 "",
1931 "do_statuscheck() {",
1932 " if [ -f $PIDFILE ]",
1933 " then",
1934 " read PID <$PIDFILE",
1935 " if [ -z \"$PID\" ]",
1936 " then",
1937 " echo \"$NAME is not running.\"",
1938 " rm -f $PIDFILE > /dev/null",
1939 " return 3",
1940 " fi",
1941 " if is_pid_running $PID;",
1942 " then",
1943 " echo \"$NAME (PID $PID) is running.\"",
1944 " return 0",
1945 " else",
1946 " echo \"$NAME is not running.\"",
1947 " rm -f $PIDFILE > /dev/null",
1948 " return 3",
1949 " fi",
1950 " else",
1951 " echo \"$NAME is not running.\"",
1952 " return 3",
1953 " fi",
1954 "}",
1955 "",
1956 "case \"$1\" in",
1957 " start)",
1958 " do_start",
1959 " ;;",
1960 " stop)",
1961 " do_stop",
1962 " ;;",
1963 " force-reload|reload|force-restart|restart)",
1964 " do_stop",
1965 " do_start",
1966 " ;;",
1967 " status)",
1968 " do_statuscheck",
1969 " ;;",
1970 " *)",
1971 " echo \"Usage: /etc/init.d/eleasvc{start|stop|restart|status}\"",
1972 " exit 1",
1973 " ;;",
1974 "esac",
1975 ""
1976 };
1977
1978 #define posix_daemon_script_lines linux_init_script_lines
1979 #define posix_daemon_script_lines_count (sizeof(linux_init_script_lines) / sizeof(linux_init_script_lines[0]))
1980
1981 #endif /* LINUX */
1982
1983 static char const* posix_get_script_path()
1984 {
1985 gate_size_t ndx;
1986 gate_string_t path;
1987
1988 for (ndx = 0; ndx != posix_init_script_paths_count; ++ndx)
1989 {
1990 gate_string_create_static(&path, posix_init_script_paths[ndx]);
1991 if (gate_file_dir_exists(&path) == GATE_RESULT_OK)
1992 {
1993 return posix_init_script_paths[ndx];
1994 }
1995 }
1996 return NULL;
1997 }
1998
1999 static gate_string_t* posix_create_script_file_path(gate_string_t const* service_name, gate_string_t* script_file_path)
2000 {
2001 char const* script_path = posix_get_script_path();
2002 gate_string_t path;
2003
2004 if (!script_path)
2005 {
2006 return NULL;
2007 }
2008
2009 gate_string_create_static(&path, script_path);
2010 return gate_file_build_path_string(script_file_path, &path, service_name);
2011 }
2012
2013
2014 typedef struct var_mapping
2015 {
2016 char const* script_var;
2017 gate_string_t const* script_value;
2018 } var_mapping_t;
2019
2020 static gate_string_t* expand_script_variables(
2021 gate_string_t const* entry,
2022 var_mapping_t const* mappings, gate_size_t mappings_count,
2023 gate_string_t* out_entry)
2024 {
2025 gate_size_t ndx;
2026 gate_size_t pos, len;
2027 char const* script_var;
2028 gate_string_t const* script_value;
2029
2030 gate_strbuilder_t builder;
2031 gate_strbuilder_create(&builder, 64);
2032 gate_strbuilder_append_string(&builder, entry);
2033
2034 for (ndx = 0; ndx != mappings_count; ++ndx)
2035 {
2036 script_var = mappings[ndx].script_var;
2037 script_value = mappings[ndx].script_value;
2038 len = gate_str_length(script_var);
2039 pos = gate_strbuilder_str_pos(&builder, script_var, len, 0);
2040 if (pos != GATE_STR_NPOS)
2041 {
2042 gate_strbuilder_replace(&builder, pos, len, gate_string_ptr(script_value, 0), gate_string_length(script_value));
2043 }
2044 }
2045
2046 gate_strbuilder_to_string(&builder, out_entry);
2047 gate_strbuilder_release(&builder);
2048 return out_entry;
2049 }
2050
2051 static gate_size_t create_command_args(
2052 char const* const* in_args, gate_size_t in_args_count,
2053 gate_string_t const* daemon_name, gate_string_t const* script_path,
2054 gate_string_t* out_args, gate_size_t out_arg_capacity)
2055 {
2056 gate_size_t ndx;
2057 char const* item;
2058 gate_string_t arg;
2059 var_mapping_t mappings[] =
2060 {
2061 { SCRIPT_VAR_NAME, daemon_name },
2062 { SCRIPT_VAR_SCRIPT, script_path }
2063 };
2064
2065 if (in_args_count > out_arg_capacity)
2066 {
2067 in_args_count = out_arg_capacity;
2068 }
2069
2070 for (ndx = 0; ndx != in_args_count; ++ndx)
2071 {
2072 item = in_args[ndx];
2073 gate_string_create_static(&arg, item);
2074 expand_script_variables(&arg, mappings, sizeof(mappings) / sizeof(mappings[0]), &out_args[ndx]);
2075 }
2076 return in_args_count;
2077 }
2078
2079 static gate_size_t create_start_command_args(
2080 gate_string_t const* daemon_name, gate_string_t const* script_path,
2081 gate_string_t* out_args, gate_size_t out_arg_capacity)
2082 {
2083 return create_command_args(
2084 posix_cmd_daemon_start, posix_cmd_daemon_start_count,
2085 daemon_name, script_path, out_args, out_arg_capacity);
2086 }
2087
2088 static gate_size_t create_stop_command_args(
2089 gate_string_t const* daemon_name, gate_string_t const* script_path,
2090 gate_string_t* out_args, gate_size_t out_arg_capacity)
2091 {
2092 return create_command_args(
2093 posix_cmd_daemon_stop, posix_cmd_daemon_stop_count,
2094 daemon_name, script_path, out_args, out_arg_capacity);
2095 }
2096
2097 static gate_size_t create_status_command_args(
2098 gate_string_t const* daemon_name, gate_string_t const* script_path,
2099 gate_string_t* out_args, gate_size_t out_arg_capacity)
2100 {
2101 return create_command_args(
2102 posix_cmd_daemon_status, posix_cmd_daemon_status_count,
2103 daemon_name, script_path, out_args, out_arg_capacity);
2104 }
2105
2106 static gate_size_t create_add_daemon_command_args(
2107 gate_string_t const* daemon_name, gate_string_t const* script_path,
2108 gate_string_t* out_args, gate_size_t out_arg_capacity)
2109 {
2110 return create_command_args(
2111 posix_cmd_daemon_add, posix_cmd_daemon_add_count,
2112 daemon_name, script_path, out_args, out_arg_capacity);
2113 }
2114
2115 static gate_size_t create_enable_daemon_command_args(
2116 gate_string_t const* daemon_name, gate_string_t const* script_path,
2117 gate_string_t* out_args, gate_size_t out_arg_capacity)
2118 {
2119 return create_command_args(
2120 posix_cmd_daemon_enable, posix_cmd_daemon_enable_count,
2121 daemon_name, script_path, out_args, out_arg_capacity);
2122 }
2123
2124 static gate_size_t create_disable_daemon_command_args(
2125 gate_string_t const* daemon_name, gate_string_t const* script_path,
2126 gate_string_t* out_args, gate_size_t out_arg_capacity)
2127 {
2128 return create_command_args(
2129 posix_cmd_daemon_disable, posix_cmd_daemon_disable_count,
2130 daemon_name, script_path, out_args, out_arg_capacity);
2131 }
2132
2133 static gate_size_t create_remove_daemon_command_args(
2134 gate_string_t const* daemon_name, gate_string_t const* script_path,
2135 gate_string_t* out_args, gate_size_t out_arg_capacity)
2136 {
2137 return create_command_args(
2138 posix_cmd_daemon_remove, posix_cmd_daemon_remove_count,
2139 daemon_name, script_path, out_args, out_arg_capacity);
2140 }
2141
2142
2143 gate_result_t posix_service_enum(gate_service_enum_callback_t callback, void* user_param)
2144 {
2145 gate_result_t ret = GATE_RESULT_FAILED;
2146 char const* posix_script_path = posix_get_script_path();
2147 gate_string_t script_path;
2148 gate_file_dirreader_t dir_reader;
2149 char filepath[GATE_MAX_FILEPATH_LENGTH];
2150 gate_size_t filepath_len;
2151 gate_string_t script_file;
2152 daemon_info_t daemon_info;
2153 gate_service_t service;
2154 gate_enumint_t access_bits;
2155
2156 do
2157 {
2158 if (!posix_script_path)
2159 {
2160 ret = GATE_RESULT_NOTAVAILABLE;
2161 break;
2162 }
2163
2164 gate_string_create_static(&script_path, posix_script_path);
2165 ret = gate_file_dir_open(&script_path, &dir_reader);
2166 GATE_BREAK_IF_FAILED(ret);
2167
2168 if (!callback)
2169 {
2170 /* no callback, no iteration required */
2171 break;
2172 }
2173
2174 while (0 != (filepath_len = gate_file_dir_read(&dir_reader, &filepath[0], sizeof(filepath), false)))
2175 {
2176 gate_string_create_static(&script_file, filepath);
2177 ret = gate_file_get_attributes(&script_file, NULL, &access_bits);
2178 if (GATE_FAILED(ret))
2179 {
2180 continue;
2181 }
2182 if (!GATE_FLAG_ENABLED(access_bits, GATE_FILEENTRY_ACCESS_OWNEREXECUTE))
2183 {
2184 /* only executable files can be init scripts */
2185 continue;
2186 }
2187 ret = extract_daemon_script_info(&script_file, &daemon_info);
2188 if (GATE_FAILED(ret))
2189 {
2190 continue;
2191 }
2192 gate_mem_clear(&service, sizeof(service));
2193
2194 gate_str_print_text(service.name, sizeof(service.name), daemon_info.name, sizeof(daemon_info.name));
2195 gate_str_print_text(service.description, sizeof(service.description), daemon_info.description, sizeof(daemon_info.description));
2196 gate_file_extract_path(filepath, filepath_len, service.address, sizeof(service.address), NULL, 0);
2197 /* gate_str_print_text(service.address, sizeof(service.address), filepath, filepath_len); */
2198 service.flags = 0;
2199 if (!callback(&service, user_param))
2200 {
2201 break;
2202 }
2203 }
2204 gate_file_dir_close(&dir_reader);
2205 } while (0);
2206
2207 return ret;
2208 }
2209
2210 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)
2211 {
2212 gate_result_t ret = GATE_RESULT_FAILED;
2213 char const* posix_script_path = posix_get_script_path();
2214 gate_string_t script_path;
2215 gate_file_dirreader_t dir_reader;
2216 char filepath[GATE_MAX_FILEPATH_LENGTH];
2217 gate_size_t filepath_len;
2218 gate_string_t script_file;
2219 daemon_info_t daemon_info;
2220 gate_enumint_t access_bits;
2221
2222 do
2223 {
2224 if (gate_string_is_empty(service_name))
2225 {
2226 ret = GATE_RESULT_INVALIDARG;
2227 break;
2228 }
2229
2230 if (!posix_script_path)
2231 {
2232 ret = GATE_RESULT_NOTAVAILABLE;
2233 break;
2234 }
2235
2236 gate_string_create_static(&script_path, posix_script_path);
2237 ret = gate_file_dir_open(&script_path, &dir_reader);
2238 GATE_BREAK_IF_FAILED(ret);
2239
2240 ret = GATE_RESULT_NOMATCH;
2241 while (0 != (filepath_len = gate_file_dir_read(&dir_reader, &filepath[0], sizeof(filepath), false)))
2242 {
2243 gate_string_create_static(&script_file, filepath);
2244 ret = gate_file_get_attributes(&script_file, NULL, &access_bits);
2245 if (GATE_FAILED(ret))
2246 {
2247 continue;
2248 }
2249 if (!GATE_FLAG_ENABLED(access_bits, GATE_FILEENTRY_ACCESS_OWNEREXECUTE))
2250 {
2251 /* only executable files can be init scripts */
2252 continue;
2253 }
2254 ret = extract_daemon_script_info(&script_file, &daemon_info);
2255 if (GATE_FAILED(ret))
2256 {
2257 continue;
2258 }
2259 if (!gate_string_equals_str(service_name, daemon_info.name))
2260 {
2261 continue;
2262 }
2263
2264 if (ptr_script_path)
2265 {
2266 gate_string_create(ptr_script_path, filepath, filepath_len);
2267 }
2268 if (ptr_daemon_info)
2269 {
2270 gate_mem_copy(ptr_daemon_info, &daemon_info, sizeof(daemon_info));
2271 }
2272 ret = GATE_RESULT_OK;
2273 break;
2274 }
2275 gate_file_dir_close(&dir_reader);
2276 if (GATE_FAILED(ret))
2277 {
2278 ret = GATE_RESULT_NOTAVAILABLE;
2279 }
2280 } while (0);
2281
2282 return ret;
2283 }
2284
2285 gate_result_t gate_services_enum(gate_service_enum_callback_t callback, void* user_param)
2286 {
2287 return posix_service_enum(callback, user_param);
2288 }
2289
2290
2291 static gate_result_t run_process_with_output_callback(
2292 gate_string_t const* program,
2293 gate_string_t const* args,
2294 gate_size_t args_count,
2295 gate_service_message_callback_t msg_callback, void* user_param,
2296 int* exit_code)
2297 {
2298 gate_result_t ret = GATE_RESULT_FAILED;
2299 gate_enumint_t start_flags = GATE_PROCESS_START_NOINHERIT | GATE_PROCESS_START_NEWTERMINAL;
2300 gate_process_handle_t proc_handle = NULL;
2301 gate_process_stream_t* proc_stream = NULL;
2302 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
2303 gate_size_t buffer_used = 0;
2304 gate_string_t msg;
2305
2306 do
2307 {
2308 ret = gate_process_start(program, args, args_count, NULL, NULL, 0, start_flags, &proc_handle, NULL, &proc_stream);
2309 GATE_BREAK_IF_FAILED(ret);
2310
2311 if (proc_stream == NULL)
2312 {
2313 break;
2314 }
2315
2316 while (GATE_SUCCEEDED(ret))
2317 {
2318 ret = gate_stream_read(proc_stream, buffer, sizeof(buffer), &buffer_used);
2319 GATE_BREAK_IF_FAILED(ret);
2320 if (buffer_used == 0)
2321 {
2322 /* end of process stream reached */
2323 break;
2324 }
2325 if (msg_callback)
2326 {
2327 gate_string_create_static_len(&msg, buffer, buffer_used);
2328 msg_callback(&msg, user_param);
2329 }
2330 }
2331
2332 if (GATE_FAILED(ret))
2333 {
2334 ret = gate_process_kill(&proc_handle);
2335 }
2336
2337 if (GATE_SUCCEEDED(ret) && (exit_code != NULL))
2338 {
2339 ret = gate_process_get_exitcode(&proc_handle, exit_code);
2340 }
2341 } while (0);
2342
2343 if (proc_handle)
2344 {
2345 gate_process_close(&proc_handle);
2346 }
2347
2348 return ret;
2349 }
2350
2351
2352 static gate_result_t run_generated_command(gate_string_t const* name,
2353 gate_service_message_callback_t msg_callback, void* user_param,
2354 gate_size_t(*cmd_generator)(gate_string_t const*, gate_string_t const*, gate_string_t*, gate_size_t))
2355 {
2356 gate_result_t ret;
2357 gate_string_t script_path = GATE_STRING_INIT_EMPTY;
2358 gate_string_t daemon_name = GATE_STRING_INIT_EMPTY;
2359 daemon_info_t daemon_info;
2360 gate_string_t args[16];
2361 gate_size_t ndx;
2362 gate_size_t args_used = 0;
2363 int script_exit_code = 0;
2364
2365 do
2366 {
2367 gate_mem_clear(args, sizeof(args));
2368 ret = posix_resolve_script(name, &script_path, &daemon_info);
2369 GATE_BREAK_IF_FAILED(ret);
2370
2371 gate_string_create_static(&daemon_name, daemon_info.name);
2372 args_used = cmd_generator(&daemon_name, &script_path, args, sizeof(args) / sizeof(args[0]));
2373
2374 ret = run_process_with_output_callback(&args[0], &args[1], args_used - 1, msg_callback, user_param, &script_exit_code);
2375 GATE_BREAK_IF_FAILED(ret);
2376
2377 if (script_exit_code != 0)
2378 {
2379 ret = GATE_RESULT_EXECUTIONFAILED;
2380 }
2381 } while (0);
2382
2383 gate_string_release(&script_path);
2384 for (ndx = 0; ndx != args_used; ++ndx)
2385 {
2386 gate_string_release(&args[ndx]);
2387 }
2388 return ret;
2389 }
2390
2391 gate_result_t gate_service_start(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
2392 {
2393 return run_generated_command(name, msg_callback, user_param, &create_start_command_args);
2394 }
2395
2396 gate_result_t gate_service_stop(gate_string_t const* name, gate_uint32_t wait_timeout, gate_bool_t force,
2397 gate_service_message_callback_t msg_callback, void* user_param)
2398 {
2399 return run_generated_command(name, msg_callback, user_param, &create_stop_command_args);
2400 }
2401
2402 gate_result_t gate_service_get_config(gate_string_t const* name, gate_service_config_t* config)
2403 {
2404 return GATE_RESULT_NOTIMPLEMENTED;
2405 }
2406
2407 gate_result_t gate_service_get_status(gate_string_t const* name, gate_enumint_t* state, gate_string_t* process_id)
2408 {
2409 gate_result_t ret = run_generated_command(name, NULL, NULL, &create_status_command_args);
2410
2411 switch (ret)
2412 {
2413 case GATE_RESULT_OK:
2414 {
2415 if (state)
2416 {
2417 *state = GATE_SERVICE_STATE_RUNNING;
2418 }
2419 if (process_id)
2420 {
2421 gate_string_create_empty(process_id);
2422 }
2423 break;
2424 }
2425 case GATE_RESULT_EXECUTIONFAILED:
2426 {
2427 if (state)
2428 {
2429 *state = GATE_SERVICE_STATE_STOPPED;
2430 }
2431 if (process_id)
2432 {
2433 gate_string_create_empty(process_id);
2434 }
2435 ret = GATE_RESULT_OK;
2436 break;
2437 }
2438 default:
2439 {
2440 if (state)
2441 {
2442 *state = GATE_SERVICE_STATE_UNKNOWN;
2443 }
2444 break;
2445 }
2446 }
2447
2448 return ret;
2449 }
2450
2451
2452 #if defined(GATE_SYS_BSD)
2453
2454 #else /* defined(GATE_SYS_LINUX) */
2455
2456 #endif
2457
2458
2459 gate_result_t create_init_script_code(
2460 gate_string_t const* name, gate_string_t const* daemon_path, gate_string_t const* daemon_args,
2461 gate_string_t const* descr, gate_uint32_t flags, gate_string_t const* dependencies,
2462 gate_string_t* script_code)
2463 {
2464 gate_result_t ret = GATE_RESULT_FAILED;
2465 gate_size_t ndx;
2466 gate_strbuilder_t script_builder = GATE_INIT_EMPTY;
2467 char const* line;
2468 gate_size_t linelen;
2469 gate_string_t linesrc;
2470 gate_string_t expanded_line;
2471 var_mapping_t var_mapping[] = {
2472 { SCRIPT_VAR_NAME, name },
2473 { SCRIPT_VAR_DAEMON, daemon_path },
2474 { SCRIPT_VAR_ARGS, daemon_args },
2475 { SCRIPT_VAR_DESCR, descr }
2476 };
2477
2478 do
2479 {
2480 gate_strbuilder_create(&script_builder, 2048 + 1024);
2481
2482 for (ndx = 0; ndx != posix_daemon_script_lines_count; ++ndx)
2483 {
2484 line = posix_daemon_script_lines[ndx];
2485 linelen = gate_str_length(line);
2486
2487 gate_string_create_static_len(&linesrc, line, linelen);
2488 if (NULL != expand_script_variables(&linesrc, var_mapping, sizeof(var_mapping) / sizeof(var_mapping[0]), &expanded_line))
2489 {
2490 gate_strbuilder_append_string(&script_builder, &expanded_line);
2491 gate_strbuilder_append_cstr(&script_builder, "\n");
2492 gate_string_release(&expanded_line);
2493 }
2494 }
2495 if (NULL == gate_strbuilder_to_string(&script_builder, script_code))
2496 {
2497 ret = GATE_RESULT_OUTOFMEMORY;
2498 break;
2499 }
2500
2501 /* success case: */
2502 ret = GATE_RESULT_OK;
2503 } while (0);
2504
2505 gate_strbuilder_release(&script_builder);
2506 return ret;
2507 }
2508
2509 gate_result_t gate_service_register(gate_string_t const* name, gate_string_t const* command, gate_string_t const* descr,
2510 gate_uint32_t flags, gate_string_t const* dependencies,
2511 gate_service_message_callback_t msg_callback, void* user_param)
2512 {
2513 gate_result_t ret;
2514 gate_string_t daemon_path = GATE_STRING_INIT_EMPTY;
2515 gate_string_t daemon_args = GATE_STRING_INIT_EMPTY;
2516 gate_string_t script_code = GATE_STRING_INIT_EMPTY;
2517 gate_string_t updater_path = GATE_STRING_INIT_EMPTY;
2518 gate_string_t script_file_path = GATE_STRING_INIT_EMPTY;
2519 gate_filestream_t* ptr_filestrm = NULL;
2520 gate_size_t lenwritten = 0;
2521
2522
2523 do
2524 {
2525 /* TODO: split command into path + args */
2526 gate_string_duplicate(&daemon_path, command);
2527
2528 ret = create_init_script_code(name, &daemon_path, &daemon_args, descr, flags, dependencies, &script_code);
2529 GATE_BREAK_IF_FAILED(ret);
2530
2531 if (NULL == posix_create_script_file_path(name, &script_file_path))
2532 {
2533 ret = GATE_RESULT_OUTOFMEMORY;
2534 break;
2535 }
2536
2537 ret = gate_file_openstream(&script_file_path, GATE_STREAM_OPEN_WRITE, &ptr_filestrm);
2538 GATE_BREAK_IF_FAILED(ret);
2539 ret = gate_stream_write_block((gate_stream_t*)ptr_filestrm, gate_string_ptr(&script_code, 0), gate_string_length(&script_code), &lenwritten);
2540 GATE_BREAK_IF_FAILED(ret);
2541
2542 gate_object_release(ptr_filestrm);
2543 ptr_filestrm = NULL;
2544
2545 run_generated_command(name, msg_callback, user_param, &create_add_daemon_command_args);
2546 run_generated_command(name, msg_callback, user_param, &create_enable_daemon_command_args);
2547
2548 } while (0);
2549
2550 gate_string_release(&daemon_path);
2551 gate_string_release(&daemon_args);
2552 gate_string_release(&script_code);
2553 gate_string_release(&updater_path);
2554 gate_string_release(&script_file_path);
2555 if (ptr_filestrm)
2556 {
2557 gate_object_release(ptr_filestrm);
2558 }
2559 return ret;
2560 }
2561
2562 gate_result_t gate_service_unregister(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
2563 {
2564 gate_result_t ret = GATE_RESULT_FAILED;
2565 gate_string_t script_file_path = GATE_STRING_INIT_EMPTY;
2566
2567 do
2568 {
2569 run_generated_command(name, msg_callback, user_param, &create_disable_daemon_command_args);
2570 run_generated_command(name, msg_callback, user_param, &create_remove_daemon_command_args);
2571
2572 if (NULL == posix_create_script_file_path(name, &script_file_path))
2573 {
2574 ret = GATE_RESULT_OUTOFMEMORY;
2575 break;
2576 }
2577
2578 if (GATE_RESULT_OK == gate_file_exists(&script_file_path))
2579 {
2580 ret = gate_file_delete(&script_file_path);
2581 GATE_BREAK_IF_FAILED(ret);
2582 }
2583
2584 ret = GATE_RESULT_OK;
2585 } while (0);
2586
2587 gate_string_release(&script_file_path);
2588
2589 return ret;
2590 }
2591
2592 #endif /* GATE_SYSTEM_SERVICES_POSIX_IMPL */
2593
2594
2595 #if defined(GATE_SYSTEM_SERVICES_NO_IMPL)
2596
2597 gate_result_t gate_services_enum(gate_service_enum_callback_t callback, void* user_param)
2598 {
2599 (void)callback;
2600 (void)user_param;
2601 return GATE_RESULT_NOTIMPLEMENTED;
2602 }
2603
2604 gate_result_t gate_service_start(gate_string_t const* name, gate_service_message_callback_t msg_callback, void* user_param)
2605 {
2606 (void)name;
2607 (void)msg_callback;
2608 (void)user_param;
2609 return GATE_RESULT_NOTIMPLEMENTED;
2610 }
2611
2612 gate_result_t gate_service_stop(gate_string_t const* name, gate_uint32_t wait_timeout, gate_bool_t force,
2613 gate_service_message_callback_t msg_callback, void* user_param)
2614 {
2615 (void)name;
2616 (void)wait_timeout;
2617 (void)force;
2618 (void)msg_callback;
2619 (void)user_param;
2620 return GATE_RESULT_NOTIMPLEMENTED;
2621 }
2622
2623 gate_result_t gate_service_get_config(gate_string_t const* name, gate_service_config_t* config)
2624 {
2625 (void)name;
2626 (void)config;
2627 return GATE_RESULT_NOTIMPLEMENTED;
2628 }
2629
2630 gate_result_t gate_service_get_status(gate_string_t const* name, gate_enumint_t* state, gate_string_t* process_id)
2631 {
2632 (void)name;
2633 (void)state;
2634 (void)process_id;
2635 return GATE_RESULT_NOTIMPLEMENTED;
2636 }
2637
2638 gate_result_t gate_service_register(gate_string_t const* name, gate_string_t const* command, gate_string_t const* descr,
2639 gate_uint32_t flags, gate_string_t const* dependencies,
2640 gate_service_message_callback_t msg_callback, void* user_param)
2641 {
2642 (void)name;
2643 (void)command;
2644 (void)descr;
2645 (void)flags;
2646 (void)dependencies;
2647 (void)msg_callback;
2648 (void)user_param;
2649 return GATE_RESULT_NOTIMPLEMENTED;
2650 }
2651
2652 gate_result_t gate_service_unregister(gate_string_t const* name,
2653 gate_service_message_callback_t msg_callback, void* user_param)
2654 {
2655 (void)name;
2656 (void)msg_callback;
2657 (void)user_param;
2658 return GATE_RESULT_NOTIMPLEMENTED;
2659 }
2660
2661
2662 #endif /* GATE_SYSTEM_SERVICES_NO_IMPL */
2663