You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

277 lines
8.5 KiB
C++

22 years ago
#include "nssm.h"
SERVICE_STATUS service_status;
SERVICE_STATUS_HANDLE service_handle;
HANDLE wait_handle;
HANDLE pid;
char exe[MAX_PATH];
char flags[MAX_PATH];
char dir[MAX_PATH];
/* Connect to the service manager */
SC_HANDLE open_service_manager() {
SC_HANDLE ret = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
if (! ret) {
eventprintf(EVENTLOG_ERROR_TYPE, "Unable to connect to service manager!\nPerhaps you need to be an administrator...");
return 0;
}
return ret;
}
19 years ago
/* About to install the service */
int pre_install_service(int argc, char **argv) {
/* Show the dialogue box if we didn't give the */
if (argc < 2) return nssm_gui(IDD_INSTALL, argv[0]);
/* Arguments are optional */
char *flags;
if (argc == 2) flags = "";
else flags = argv[2];
return install_service(argv[0], argv[1], flags);
}
/* About to remove the service */
int pre_remove_service(int argc, char **argv) {
/* Show dialogue box if we didn't pass service name and "confirm" */
if (argc < 2) return nssm_gui(IDD_REMOVE, argv[0]);
if (str_equiv(argv[1], "confirm")) return remove_service(argv[0]);
fprintf(stderr, "To remove a service without confirmation: nssm remove <servicename> confirm\n");
return 100;
}
22 years ago
/* Install the service */
19 years ago
int install_service(char *name, char *exe, char *flags) {
/* Open service manager */
SC_HANDLE services = open_service_manager();
if (! services) {
fprintf(stderr, "Error opening service manager!\n");
return 2;
}
/* Get path of this program */
char path[MAX_PATH];
GetModuleFileName(0, path, MAX_PATH);
/* Construct command */
char command[MAX_PATH];
int runlen = strlen(NSSM_RUN);
int pathlen = strlen(path);
if (pathlen + runlen + 2 >= MAX_PATH) {
fprintf(stderr, "The full path to " NSSM " is too long!\n");
return 3;
}
if (snprintf(command, sizeof(command), "\"%s\" %s", path, NSSM_RUN) < 0) {
fprintf(stderr, "Out of memory for ImagePath!\n");
return 4;
}
/* Work out directory name */
unsigned int len = strlen(exe);
unsigned int i;
for (i = len; i && exe[i] != '\\' && exe[i] != '/'; i--);
char dir[MAX_PATH];
memmove(dir, exe, i);
dir[i] = '\0';
/* Create the service */
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);
if (! service) {
fprintf(stderr, "Error creating service!\n");
CloseServiceHandle(services);
return 5;
}
/* Now we need to put the parameters into the registry */
if (create_parameters(name, exe, flags, dir)) {
fprintf(stderr, "Error setting startup parameters for the service!\n");
DeleteService(service);
CloseServiceHandle(services);
return 6;
}
/* Cleanup */
CloseServiceHandle(service);
CloseServiceHandle(services);
printf("Service \"%s\" installed successfully!\n", name);
return 0;
22 years ago
}
/* Remove the service */
int remove_service(char *name) {
19 years ago
/* Open service manager */
SC_HANDLE services = open_service_manager();
if (! services) {
fprintf(stderr, "Error opening service manager!\n");
return 2;
}
/* Try to open the service */
SC_HANDLE service = OpenService(services, name, SC_MANAGER_ALL_ACCESS);
if (! service) {
fprintf(stderr, "Can't open service!");
CloseServiceHandle(services);
return 3;
}
/* Try to delete the service */
if (! DeleteService(service)) {
fprintf(stderr, "Error deleting service!\n");
CloseServiceHandle(service);
CloseServiceHandle(services);
return 4;
}
/* Cleanup */
CloseServiceHandle(service);
CloseServiceHandle(services);
printf("Service \"%s\" removed successfully!\n", name);
return 0;
22 years ago
}
/* Service initialisation */
void WINAPI service_main(unsigned long argc, char **argv) {
/* Initialise status */
ZeroMemory(&service_status, sizeof(service_status));
service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
service_status.dwCurrentState = SERVICE_RUNNING;
service_status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
service_status.dwWin32ExitCode = NO_ERROR;
service_status.dwServiceSpecificExitCode = 0;
service_status.dwCheckPoint = 0;
service_status.dwWaitHint = 1000;
/* Signal we AREN'T running the server */
pid = 0;
/* Get startup parameters */
int ret = get_parameters(argv[0], exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir));
if (ret) {
eventprintf(EVENTLOG_ERROR_TYPE, "service_main(): Can't get startup parameters: error %d", ret);
return;
}
/* Register control handler */
service_handle = RegisterServiceCtrlHandlerEx(NSSM, service_control_handler, 0);
if (! service_handle) {
eventprintf(EVENTLOG_ERROR_TYPE, "service_main(): RegisterServiceCtrlHandlerEx() failed: %s", error_string(GetLastError()));
return;
}
monitor_service();
}
int monitor_service() {
/* Set service status to started */
int ret = start_service();
if (ret) {
eventprintf(EVENTLOG_ERROR_TYPE, "Can't start service: error code %d", ret);
return ret;
}
eventprintf(EVENTLOG_INFORMATION_TYPE, "Started process %s %s in %s", exe, flags, dir);
/* Monitor service service */
if (! RegisterWaitForSingleObject(&wait_handle, pid, end_service, 0, INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTELONGFUNCTION)) {
eventprintf(EVENTLOG_WARNING_TYPE, "RegisterWaitForSingleObject() returned %s - service may claim to be still running when %s exits ", error_string(GetLastError()), exe);
}
return 0;
}
/* Service control handler */
unsigned long WINAPI service_control_handler(unsigned long control, unsigned long event, void *data, void *context) {
switch (control) {
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
stop_service(0);
return NO_ERROR;
}
/* Unknown control */
return ERROR_CALL_NOT_IMPLEMENTED;
}
/* Start the service */
int start_service() {
if (pid) return 0;
/* Allocate a STARTUPINFO structure for a new process */
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
/* Allocate a PROCESSINFO structure for the process */
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
/* Launch executable with arguments */
char cmd[MAX_PATH];
if (_snprintf(cmd, sizeof(cmd), "%s %s", exe, flags) < 0) {
eventprintf(EVENTLOG_ERROR_TYPE, "Error constructing command line");
return stop_service(2);
}
if (! CreateProcess(0, cmd, 0, 0, 0, 0, 0, dir, &si, &pi)) {
eventprintf(EVENTLOG_ERROR_TYPE, "Can't launch %s. CreateProcess() returned %s", exe, error_string(GetLastError()));
return stop_service(3);
}
pid = pi.hProcess;
/* Signal successful start */
service_status.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(service_handle, &service_status);
return 0;
}
/* Stop the service */
int stop_service(unsigned long exitcode) {
/* Signal we are stopping */
service_status.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(service_handle, &service_status);
/* Nothing to do if server isn't running */
if (pid) {
/* Shut down server */
TerminateProcess(pid, 0);
pid = 0;
}
/* Signal we stopped */
service_status.dwCurrentState = SERVICE_STOPPED;
if (exitcode) {
service_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
service_status.dwServiceSpecificExitCode = exitcode;
}
else {
service_status.dwWin32ExitCode = NO_ERROR;
service_status.dwServiceSpecificExitCode = 0;
}
SetServiceStatus(service_handle, &service_status);
return exitcode;
}
/* Callback function triggered when the server exits */
void CALLBACK end_service(void *arg, unsigned char why) {
/* Check exit code */
unsigned long ret = 0;
GetExitCodeProcess(pid, &ret);
/* Force an error code if none given, so system can restart this service */
/*if (! ret) {
eventprintf(EVENTLOG_INFORMATION_TYPE, "Process exited with return code 0 - overriding with return code 111 so the service manager will notice the failure");
ret = 111;
}
else */eventprintf(EVENTLOG_INFORMATION_TYPE, "Process %s exited with return code %u", exe, ret);
/* Try to restart the service or return failure code to service manager */
pid = 0;
while (monitor_service()) {
eventprintf(EVENTLOG_INFORMATION_TYPE, "Failed to restart %s - sleeping ", exe, ret);
Sleep(30000);
}
}