static int CmdStopService(void) { SERVICE_STATUS svcstatus; DWORD status; /* Open the service manager and find its status */ if (status = get_service_status(&svcstatus, TRUE)) return service_error(status, "Unable to access service details"); if (svcstatus.dwCurrentState != SERVICE_RUNNING) return service_error(0, "The service is not currently running."); /* Everything is fine, so stop the service */ if (!ControlService(service, SERVICE_CONTROL_STOP, &svcstatus)) return service_error(GetLastError(), "Cannot stop service"); close_service_handles(); fprintf(stderr, "Stop request sent to service\n"); return FALSE; } /* end of CmdStopService */
static int CmdRemoveService(void) { SERVICE_STATUS svcstatus; DWORD status; /* Open the service manager and find its status */ if (status = get_service_status(&svcstatus, TRUE)) return service_error(status, "Unable to access service details"); /* Check to see that the service is not running. */ if (svcstatus.dwCurrentState != SERVICE_STOPPED) return service_error(0, "You must stop the service before you can remove it."); /* Everything is fine, so delete the service definition. */ if (!DeleteService(service)) return service_error(GetLastError(), "Cannot remove service"); close_service_handles(); fprintf(stderr, "Service successfully removed\n"); return FALSE; } /* end of CmdRemoveService */
static int CmdStartService(void) { SERVICE_STATUS svcstatus; DWORD status; /* Open the service manager and find its status */ if (status = get_service_status(&svcstatus, TRUE)) return service_error(status, "Unable to access service details"); if (svcstatus.dwCurrentState != SERVICE_STOPPED) return service_error(0, "The service is not currently stopped."); /* Everything is fine, so start the service */ if (!StartService(service, 0, NULL)) return service_error(GetLastError(), "Cannot start service"); close_service_handles(); fprintf(stderr, "Start request sent to service\n"); return FALSE; } /* end of CmdStartService */
static void service_process_status_timeout(struct service_process *process) { service_error(process->service, "Initial status notification not received in %d " "seconds, killing the process", SERVICE_FIRST_STATUS_TIMEOUT_SECS); if (kill(process->pid, SIGKILL) < 0 && errno != ESRCH) { service_error(process->service, "kill(%s, SIGKILL) failed: %m", dec2str(process->pid)); } timeout_remove(&process->to_status); }
/* Open a handle to the Service. */ static int get_service(void) { service = OpenService(SCmanager, THIS_SERVICE, SERVICE_ALL_ACCESS); if (!service) return service_error(GetLastError(), "Cannot access service definition"); return FALSE; } /* end of get_service */
static int open_service_manager(void) { SCmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (!SCmanager) return service_error(GetLastError(), "Unable to talk to the Service Control Manager"); return FALSE; } /* end of openServiceManager */
static int CmdInstallService(int argc, char *argv[]) { char fullfilename[MAX_PATH]; /* Pick up our full path and file name. */ if (!GetModuleFileName(NULL, fullfilename, sizeof(fullfilename))) return service_error(GetLastError(), "Cannot locate full filename"); /* Open a handle to the Service Control Manager. */ if (open_service_manager()) return TRUE; /* Now create the service definition. */ service = CreateService(SCmanager, THIS_SERVICE, THIS_SERVICE_DISPLAY, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullfilename, NULL, /* no load ordering group */ NULL, /* no tag identifier */ NULL, /* no dependencies */ NULL, /* LocalSystem account */ NULL); /* no password */ if (!service) return service_error(GetLastError(), "Unable to create service"); close_service_handles(); fprintf(stderr, "Service successfully installed\n"); return FALSE; } /* end of CmdInstallService */
void service_anvil_process_created(struct service_process *process) { struct service_anvil_global *anvil = service_anvil_global; const char *error; service_anvil_global->pid = process->pid; service_anvil_global->uid = process->uid; service_anvil_global->process_count++; service_list_anvil_discard_input_stop(anvil); if (anvil_send_handshake(anvil->blocking_fd[1], &error) < 0 || anvil_send_handshake(anvil->nonblocking_fd[1], &error) < 0) service_error(process->service, "%s", error); }
static int CmdStatusService(void) { SERVICE_STATUS svcstatus; DWORD status; char *p; /* Open the service manager and find its status */ if (status = get_service_status(&svcstatus, FALSE)) return service_error(status, "Unable to access service details"); switch (svcstatus.dwCurrentState) { case SERVICE_STOPPED: p = "The service is not running."; break; case SERVICE_START_PENDING: p = "The service is starting."; break; case SERVICE_STOP_PENDING: p = "The service is stopping."; break; case SERVICE_RUNNING: p = "The service is running."; break; case SERVICE_CONTINUE_PENDING: p = "The service continue is pending."; break; case SERVICE_PAUSE_PENDING: p = "The service pause is pending."; break; case SERVICE_PAUSED: p = "The service is paused."; break; default: p = "Unrecognised status."; break; } /* end of switch */ fprintf(stderr, "%s\n", p); return FALSE; } /* end of CmdStatusService */
static VOID worker_thread(VOID * notused) { int argc = 3; char fullfilename[MAX_PATH]; char directory[MAX_PATH]; static const char configname[] = "mush.cnf"; static const char errorlogname[] = "log\\game.log"; char *argv[3] = { fullfilename, configname, errorlogname }; char *p; if (!GetModuleFileName(NULL, fullfilename, sizeof(fullfilename))) { service_error(GetLastError(), "Cannot locate full filename"); Win32_Exit(1); } /* remove last part of file name to get working directory */ strcpy(directory, fullfilename); p = strrchr(directory, '\\'); if (p) *p = 0; /* make sure we are running in the MUSH directory */ _chdir(directory); /* if running as a service, redirect stderr to a log file. */ if (threadHandle) freopen("log\\game.log", "w", stderr); /* handle shutdowns and ctrl-c */ SetConsoleCtrlHandler(shut_down_handler, TRUE); /* start up the main MUSH code */ exit(mainthread(argc, argv)); } /* end of worker_thread */
struct service_process *service_process_create(struct service *service) { static unsigned int uid_counter = 0; struct service_process *process; unsigned int uid = ++uid_counter; const char *hostdomain; pid_t pid; bool process_forked; i_assert(service->status_fd[0] != -1); if (service->to_throttle != NULL) { /* throttling service, don't create new processes */ return NULL; } if (service->list->destroying) { /* these services are being destroyed, no point in creating new processes now */ return NULL; } /* look this up before fork()ing so that it gets cached for all the future lookups. */ hostdomain = my_hostdomain(); if (service->type == SERVICE_TYPE_ANVIL && service_anvil_global->pid != 0) { pid = service_anvil_global->pid; uid = service_anvil_global->uid; process_forked = FALSE; } else { pid = fork(); process_forked = TRUE; service->list->fork_counter++; } if (pid < 0) { service_error(service, "fork() failed: %m"); return NULL; } if (pid == 0) { /* child */ service_process_setup_environment(service, uid, hostdomain); service_reopen_inet_listeners(service); service_dup_fds(service); drop_privileges(service); process_exec(service->executable, NULL); } i_assert(hash_table_lookup(service_pids, POINTER_CAST(pid)) == NULL); process = i_new(struct service_process, 1); process->service = service; process->refcount = 1; process->pid = pid; process->uid = uid; if (process_forked) { process->to_status = timeout_add(SERVICE_FIRST_STATUS_TIMEOUT_SECS * 1000, service_process_status_timeout, process); } process->available_count = service->client_limit; service->process_count++; service->process_avail++; DLLIST_PREPEND(&service->processes, process); service_list_ref(service->list); hash_table_insert(service_pids, POINTER_CAST(process->pid), process); if (service->type == SERVICE_TYPE_ANVIL && process_forked) service_anvil_process_created(process); return process; }