3 SERVICE_STATUS service_status;
\r
4 SERVICE_STATUS_HANDLE service_handle;
\r
8 char flags[MAX_PATH];
\r
11 /* Connect to the service manager */
\r
12 SC_HANDLE open_service_manager() {
\r
13 SC_HANDLE ret = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
\r
15 eventprintf(EVENTLOG_ERROR_TYPE, "Unable to connect to service manager!\nPerhaps you need to be an administrator...");
\r
22 /* Install the service */
\r
23 int install_service(char *name) {
\r
25 /* Show the dialogue box */
\r
26 return nssm_gui(IDD_INSTALL, name);
\r
28 fprintf(stderr, "Unimplemented\n");
\r
33 /* Remove the service */
\r
34 int remove_service(char *name) {
\r
36 return nssm_gui(IDD_REMOVE, name);
\r
38 fprintf(stderr, "Unimplemented\n");
\r
43 /* Service initialisation */
\r
44 void WINAPI service_main(unsigned long argc, char **argv) {
\r
45 /* Initialise status */
\r
46 ZeroMemory(&service_status, sizeof(service_status));
\r
47 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
\r
48 service_status.dwCurrentState = SERVICE_RUNNING;
\r
49 service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
\r
50 service_status.dwWin32ExitCode = NO_ERROR;
\r
51 service_status.dwServiceSpecificExitCode = 0;
\r
52 service_status.dwCheckPoint = 0;
\r
53 service_status.dwWaitHint = 1000;
\r
55 /* Signal we AREN'T running the server */
\r
58 /* Get startup parameters */
\r
59 int ret = get_parameters(argv[0], exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir));
\r
61 eventprintf(EVENTLOG_ERROR_TYPE, "service_main(): Can't get startup parameters: error %d", ret);
\r
65 /* Register control handler */
\r
66 service_handle = RegisterServiceCtrlHandlerEx(NSSM, service_control_handler, 0);
\r
67 if (! service_handle) {
\r
68 eventprintf(EVENTLOG_ERROR_TYPE, "service_main(): RegisterServiceCtrlHandlerEx() failed: %s", error_string(GetLastError()));
\r
75 int monitor_service() {
\r
76 /* Set service status to started */
\r
77 int ret = start_service();
\r
79 eventprintf(EVENTLOG_ERROR_TYPE, "Can't start service: error code %d", ret);
\r
82 eventprintf(EVENTLOG_INFORMATION_TYPE, "Started process %s %s in %s", exe, flags, dir);
\r
84 /* Monitor service service */
\r
85 if (! RegisterWaitForSingleObject(&wait_handle, pid, end_service, 0, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTELONGFUNCTION)) {
\r
86 eventprintf(EVENTLOG_WARNING_TYPE, "RegisterWaitForSingleObject() returned %s - service may claim to be still running when %s exits ", error_string(GetLastError()), exe);
\r
92 /* Service control handler */
\r
93 unsigned long WINAPI service_control_handler(unsigned long control, unsigned long event, void *data, void *context) {
\r
95 case SERVICE_CONTROL_SHUTDOWN:
\r
96 case SERVICE_CONTROL_STOP:
\r
101 /* Unknown control */
\r
102 return ERROR_CALL_NOT_IMPLEMENTED;
\r
105 /* Start the service */
\r
106 int start_service() {
\r
109 /* Allocate a STARTUPINFO structure for a new process */
\r
111 ZeroMemory(&si, sizeof(si));
\r
112 si.cb = sizeof(si);
\r
114 /* Allocate a PROCESSINFO structure for the process */
\r
115 PROCESS_INFORMATION pi;
\r
116 ZeroMemory(&pi, sizeof(pi));
\r
118 /* Launch executable with arguments */
\r
119 char cmd[MAX_PATH];
\r
120 if (_snprintf(cmd, sizeof(cmd), "%s %s", exe, flags) < 0) {
\r
121 eventprintf(EVENTLOG_ERROR_TYPE, "Error constructing command line");
\r
122 return stop_service(2);
\r
124 if (! CreateProcess(0, cmd, 0, 0, 0, 0, 0, dir, &si, &pi)) {
\r
125 eventprintf(EVENTLOG_ERROR_TYPE, "Can't launch %s. CreateProcess() returned %s", exe, error_string(GetLastError()));
\r
126 return stop_service(3);
\r
130 /* Signal successful start */
\r
131 service_status.dwCurrentState = SERVICE_RUNNING;
\r
132 SetServiceStatus(service_handle, &service_status);
\r
137 /* Stop the service */
\r
138 int stop_service(unsigned long exitcode) {
\r
139 /* Signal we are stopping */
\r
140 service_status.dwCurrentState = SERVICE_STOP_PENDING;
\r
141 SetServiceStatus(service_handle, &service_status);
\r
143 /* Nothing to do if server isn't running */
\r
145 /* Shut down server */
\r
146 TerminateProcess(pid, 0);
\r
150 /* Signal we stopped */
\r
151 service_status.dwCurrentState = SERVICE_STOPPED;
\r
153 service_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
\r
154 service_status.dwServiceSpecificExitCode = exitcode;
\r
157 service_status.dwWin32ExitCode = NO_ERROR;
\r
158 service_status.dwServiceSpecificExitCode = 0;
\r
160 SetServiceStatus(service_handle, &service_status);
\r
165 /* Callback function triggered when the server exits */
\r
166 void CALLBACK end_service(void *arg, unsigned char why) {
\r
167 /* Check exit code */
\r
168 unsigned long ret = 0;
\r
169 GetExitCodeProcess(pid, &ret);
\r
171 /* Force an error code if none given, so system can restart this service */
\r
173 eventprintf(EVENTLOG_INFORMATION_TYPE, "Process exited with return code 0 - overriding with return code 111 so the service manager will notice the failure");
\r
176 else */eventprintf(EVENTLOG_INFORMATION_TYPE, "Process %s exited with return code %u", exe, ret);
\r
178 /* Try to restart the service or return failure code to service manager */
\r
180 while (monitor_service()) {
\r
181 eventprintf(EVENTLOG_INFORMATION_TYPE, "Failed to restart %s - sleeping ", exe, ret);
\r