2
Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; version 2 of the
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21
#include "chassis-win32-service.h"
22
#include "chassis-mainloop.h" /* for chassis_set_shutdown */
26
* win32 service functions
33
static char **shell_argv;
34
static int shell_argc;
35
static int (*shell_main)(int, char **);
36
static int chassis_win32_running_as_service = 0;
37
static SERVICE_STATUS chassis_win32_service_status;
38
static SERVICE_STATUS_HANDLE chassis_win32_service_status_handle = 0;
40
gboolean chassis_win32_is_service(void) {
41
return chassis_win32_running_as_service;
44
void chassis_win32_service_set_state(DWORD new_state, int wait_msec) {
47
/* safeguard against a missing if(chassis_win32_running_as_service) in other code */
48
if (!chassis_win32_running_as_service) return;
50
g_assert(chassis_win32_service_status_handle);
53
case SERVICE_START_PENDING:
54
case SERVICE_STOP_PENDING:
55
chassis_win32_service_status.dwWaitHint = wait_msec;
57
if (chassis_win32_service_status.dwCurrentState == new_state) {
58
chassis_win32_service_status.dwCheckPoint++;
60
chassis_win32_service_status.dwCheckPoint = 0;
65
chassis_win32_service_status.dwWaitHint = 0;
69
chassis_win32_service_status.dwCurrentState = new_state;
71
if (!SetServiceStatus (chassis_win32_service_status_handle, &chassis_win32_service_status)) {
72
status = GetLastError();
77
* the event-handler for the service
79
* the SCM will send us events from time to time which we acknoledge
82
static DWORD WINAPI chassis_win32_service_ctrl(DWORD Opcode, DWORD EventType, LPVOID EventData, LPVOID _udata) {
84
case SERVICE_CONTROL_SHUTDOWN:
85
case SERVICE_CONTROL_STOP:
86
chassis_win32_service_set_state(SERVICE_STOP_PENDING, 0);
88
chassis_set_shutdown(); /* exit the main-loop */
91
case SERVICE_CONTROL_INTERROGATE:
92
/* even if we don't implement it, we should return NO_ERROR here */
95
chassis_win32_service_set_state(Opcode, 0); /* forward the state changes */
96
return ERROR_CALL_NOT_IMPLEMENTED;
101
* trampoline us into the real main_cmdline
103
static void WINAPI chassis_win32_service_start(DWORD argc, LPTSTR *argv) {
104
const char *service_name = "MerlinAgent";
107
/* tell the service controller that we are alive */
108
chassis_win32_service_status.dwCurrentState = SERVICE_START_PENDING;
109
chassis_win32_service_status.dwCheckPoint = 0;
110
chassis_win32_service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
111
chassis_win32_service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
112
chassis_win32_service_status.dwWin32ExitCode = NO_ERROR;
113
chassis_win32_service_status.dwServiceSpecificExitCode = 0;
115
chassis_win32_service_status_handle = RegisterServiceCtrlHandlerEx(service_name, chassis_win32_service_ctrl, NULL);
117
if (chassis_win32_service_status_handle == (SERVICE_STATUS_HANDLE)0) {
118
int err = GetLastError();
120
g_critical("%s: RegisterServiceCtrlHandler(%s, ...) failed: %s (%d)",
129
chassis_win32_service_set_state(SERVICE_START_PENDING, 1000); /* wait max 1sec before we get the to the next step */
131
g_assert(shell_main);
133
/* jump into the actual main */
134
ret = shell_main(shell_argc, shell_argv);
136
/* FIXME: should we log if we fail to start ? */
140
* Determine whether we are called as a service and set that up.
141
* Then call main_cmdline to do the real work.
143
int main_win32(int argc, char **argv, int (*_main_cmdline)(int, char **)) {
146
SERVICE_TABLE_ENTRY dispatch_tab[] = {
147
{ "", chassis_win32_service_start }, /* we use SERVICE_WIN32_OWN_PROCESS, so the name can be "" */
151
if (0 != WSAStartup(MAKEWORD( 2, 2 ), &wsaData)) {
152
g_critical("WSAStartup failed to initialize the socket library.\n");
157
/* save the arguments because the service controller will clobber them */
158
shell_main = _main_cmdline;
162
/* speculate that we are running as a service, reset to 0 on error */
163
chassis_win32_running_as_service = TRUE;
165
if (!StartServiceCtrlDispatcher(dispatch_tab)) {
166
int err = GetLastError();
169
case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
170
/* we weren't called as a service, carry on with the cmdline handling */
171
chassis_win32_running_as_service = FALSE;
172
return shell_main(shell_argc, shell_argv);
173
case ERROR_SERVICE_ALREADY_RUNNING:
174
g_critical("service is already running, shutting down");
177
g_critical("unhandled error-code (%d) for StartServiceCtrlDispatcher(), shutting down", err);
181
/* the service-thread is started, return to the shell */
187
* just a stub in case we aren't on win32
189
int main_win32(int G_GNUC_UNUSED argc, char G_GNUC_UNUSED **argv, int G_GNUC_UNUSED (*_main_cmdline)(int, char **)) {