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 /* About to install the service */
\r
23 int pre_install_service(int argc, char **argv) {
\r
24 /* Show the dialogue box if we didn't give the */
\r
25 if (argc < 2) return nssm_gui(IDD_INSTALL, argv[0]);
\r
27 /* Arguments are optional */
\r
29 if (argc == 2) flags = "";
\r
30 else flags = argv[2];
\r
32 return install_service(argv[0], argv[1], flags);
\r
35 /* About to remove the service */
\r
36 int pre_remove_service(int argc, char **argv) {
\r
37 /* Show dialogue box if we didn't pass service name and "confirm" */
\r
38 if (argc < 2) return nssm_gui(IDD_REMOVE, argv[0]);
\r
39 if (str_equiv(argv[1], "confirm")) return remove_service(argv[0]);
\r
40 fprintf(stderr, "To remove a service without confirmation: nssm remove <servicename> confirm\n");
\r
44 /* Install the service */
\r
45 int install_service(char *name, char *exe, char *flags) {
\r
46 /* Open service manager */
\r
47 SC_HANDLE services = open_service_manager();
\r
49 fprintf(stderr, "Error opening service manager!\n");
\r
53 /* Get path of this program */
\r
54 char path[MAX_PATH];
\r
55 GetModuleFileName(0, path, MAX_PATH);
\r
57 /* Construct command */
\r
58 char command[MAX_PATH];
\r
59 int runlen = strlen(NSSM_RUN);
\r
60 int pathlen = strlen(path);
\r
61 if (pathlen + runlen + 2 >= MAX_PATH) {
\r
62 fprintf(stderr, "The full path to " NSSM " is too long!\n");
\r
65 if (snprintf(command, sizeof(command), "\"%s\" %s", path, NSSM_RUN) < 0) {
\r
66 fprintf(stderr, "Out of memory for ImagePath!\n");
\r
70 /* Work out directory name */
\r
71 unsigned int len = strlen(exe);
\r
73 for (i = len; i && exe[i] != '\\' && exe[i] != '/'; i--);
\r
75 memmove(dir, exe, i);
\r
78 /* Create the service */
\r
79 SC_HANDLE service = CreateService(services, name, name, SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, command, 0, 0, 0, 0, 0);
\r
81 fprintf(stderr, "Error creating service!\n");
\r
82 CloseServiceHandle(services);
\r
86 /* Now we need to put the parameters into the registry */
\r
87 if (create_parameters(name, exe, flags, dir)) {
\r
88 fprintf(stderr, "Error setting startup parameters for the service!\n");
\r
89 DeleteService(service);
\r
90 CloseServiceHandle(services);
\r
95 CloseServiceHandle(service);
\r
96 CloseServiceHandle(services);
\r
98 printf("Service \"%s\" installed successfully!\n", name);
\r
102 /* Remove the service */
\r
103 int remove_service(char *name) {
\r
104 /* Open service manager */
\r
105 SC_HANDLE services = open_service_manager();
\r
107 fprintf(stderr, "Error opening service manager!\n");
\r
111 /* Try to open the service */
\r
112 SC_HANDLE service = OpenService(services, name, SC_MANAGER_ALL_ACCESS);
\r
114 fprintf(stderr, "Can't open service!");
\r
115 CloseServiceHandle(services);
\r
119 /* Try to delete the service */
\r
120 if (! DeleteService(service)) {
\r
121 fprintf(stderr, "Error deleting service!\n");
\r
122 CloseServiceHandle(service);
\r
123 CloseServiceHandle(services);
\r
128 CloseServiceHandle(service);
\r
129 CloseServiceHandle(services);
\r
131 printf("Service \"%s\" removed successfully!\n", name);
\r
135 /* Service initialisation */
\r
136 void WINAPI service_main(unsigned long argc, char **argv) {
\r
137 /* Initialise status */
\r
138 ZeroMemory(&service_status, sizeof(service_status));
\r
139 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
\r
140 service_status.dwCurrentState = SERVICE_RUNNING;
\r
141 service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
\r
142 service_status.dwWin32ExitCode = NO_ERROR;
\r
143 service_status.dwServiceSpecificExitCode = 0;
\r
144 service_status.dwCheckPoint = 0;
\r
145 service_status.dwWaitHint = 1000;
\r
147 /* Signal we AREN'T running the server */
\r
150 /* Get startup parameters */
\r
151 int ret = get_parameters(argv[0], exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir));
\r
153 eventprintf(EVENTLOG_ERROR_TYPE, "service_main(): Can't get startup parameters: error %d", ret);
\r
157 /* Register control handler */
\r
158 service_handle = RegisterServiceCtrlHandlerEx(NSSM, service_control_handler, 0);
\r
159 if (! service_handle) {
\r
160 eventprintf(EVENTLOG_ERROR_TYPE, "service_main(): RegisterServiceCtrlHandlerEx() failed: %s", error_string(GetLastError()));
\r
167 int monitor_service() {
\r
168 /* Set service status to started */
\r
169 int ret = start_service();
\r
171 eventprintf(EVENTLOG_ERROR_TYPE, "Can't start service: error code %d", ret);
\r
174 eventprintf(EVENTLOG_INFORMATION_TYPE, "Started process %s %s in %s", exe, flags, dir);
\r
176 /* Monitor service service */
\r
177 if (! RegisterWaitForSingleObject(&wait_handle, pid, end_service, 0, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTELONGFUNCTION)) {
\r
178 eventprintf(EVENTLOG_WARNING_TYPE, "RegisterWaitForSingleObject() returned %s - service may claim to be still running when %s exits ", error_string(GetLastError()), exe);
\r
184 /* Service control handler */
\r
185 unsigned long WINAPI service_control_handler(unsigned long control, unsigned long event, void *data, void *context) {
\r
187 case SERVICE_CONTROL_SHUTDOWN:
\r
188 case SERVICE_CONTROL_STOP:
\r
193 /* Unknown control */
\r
194 return ERROR_CALL_NOT_IMPLEMENTED;
\r
197 /* Start the service */
\r
198 int start_service() {
\r
201 /* Allocate a STARTUPINFO structure for a new process */
\r
203 ZeroMemory(&si, sizeof(si));
\r
204 si.cb = sizeof(si);
\r
206 /* Allocate a PROCESSINFO structure for the process */
\r
207 PROCESS_INFORMATION pi;
\r
208 ZeroMemory(&pi, sizeof(pi));
\r
210 /* Launch executable with arguments */
\r
211 char cmd[MAX_PATH];
\r
212 if (_snprintf(cmd, sizeof(cmd), "%s %s", exe, flags) < 0) {
\r
213 eventprintf(EVENTLOG_ERROR_TYPE, "Error constructing command line");
\r
214 return stop_service(2);
\r
216 if (! CreateProcess(0, cmd, 0, 0, 0, 0, 0, dir, &si, &pi)) {
\r
217 eventprintf(EVENTLOG_ERROR_TYPE, "Can't launch %s. CreateProcess() returned %s", exe, error_string(GetLastError()));
\r
218 return stop_service(3);
\r
222 /* Signal successful start */
\r
223 service_status.dwCurrentState = SERVICE_RUNNING;
\r
224 SetServiceStatus(service_handle, &service_status);
\r
229 /* Stop the service */
\r
230 int stop_service(unsigned long exitcode) {
\r
231 /* Signal we are stopping */
\r
232 service_status.dwCurrentState = SERVICE_STOP_PENDING;
\r
233 SetServiceStatus(service_handle, &service_status);
\r
235 /* Nothing to do if server isn't running */
\r
237 /* Shut down server */
\r
238 TerminateProcess(pid, 0);
\r
242 /* Signal we stopped */
\r
243 service_status.dwCurrentState = SERVICE_STOPPED;
\r
245 service_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
\r
246 service_status.dwServiceSpecificExitCode = exitcode;
\r
249 service_status.dwWin32ExitCode = NO_ERROR;
\r
250 service_status.dwServiceSpecificExitCode = 0;
\r
252 SetServiceStatus(service_handle, &service_status);
\r
257 /* Callback function triggered when the server exits */
\r
258 void CALLBACK end_service(void *arg, unsigned char why) {
\r
259 /* Check exit code */
\r
260 unsigned long ret = 0;
\r
261 GetExitCodeProcess(pid, &ret);
\r
263 /* Force an error code if none given, so system can restart this service */
\r
265 eventprintf(EVENTLOG_INFORMATION_TYPE, "Process exited with return code 0 - overriding with return code 111 so the service manager will notice the failure");
\r
268 else */eventprintf(EVENTLOG_INFORMATION_TYPE, "Process %s exited with return code %u", exe, ret);
\r
270 /* Try to restart the service or return failure code to service manager */
\r
272 while (monitor_service()) {
\r
273 eventprintf(EVENTLOG_INFORMATION_TYPE, "Failed to restart %s - sleeping ", exe, ret);
\r