/* * %CopyrightBegin% * * Copyright Ericsson AB 1998-2009. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * %CopyrightEnd% */ #include #include #include #include #include #include "erlsrv_global.h" #include "erlsrv_registry.h" #include "erlsrv_util.h" #include "erlsrv_service.h" static HANDLE eventStop; static HANDLE eventKillErlang; static CRITICAL_SECTION crit; static SERVICE_STATUS_HANDLE statusHandle; static DWORD currentState; static void fill_status(SERVICE_STATUS *status){ status->dwServiceType = SERVICE_WIN32_OWN_PROCESS; status->dwCurrentState = 0; status->dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; status->dwWin32ExitCode = NO_ERROR; status->dwServiceSpecificExitCode = 0; status->dwCheckPoint = 0; status->dwWaitHint = 0; } static BOOL set_start_pending(int waithint, int checkpoint){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); currentState = stat.dwCurrentState = SERVICE_START_PENDING; LeaveCriticalSection(&crit); stat.dwControlsAccepted = 0; stat.dwCheckPoint = checkpoint; stat.dwWaitHint = waithint; return SetServiceStatus(statusHandle, &stat); } static BOOL set_stop_pending(int waithint, int checkpoint){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); currentState = stat.dwCurrentState = SERVICE_STOP_PENDING; LeaveCriticalSection(&crit); stat.dwControlsAccepted = 0; stat.dwCheckPoint = checkpoint; stat.dwWaitHint = waithint; return SetServiceStatus(statusHandle, &stat); } static BOOL set_running(){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); currentState = stat.dwCurrentState = SERVICE_RUNNING; LeaveCriticalSection(&crit); return SetServiceStatus(statusHandle, &stat); } static BOOL set_stopped(int error){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); currentState = stat.dwCurrentState = SERVICE_STOPPED; LeaveCriticalSection(&crit); stat.dwWin32ExitCode = error; return SetServiceStatus(statusHandle, &stat); } static BOOL reset_current(){ SERVICE_STATUS stat; fill_status(&stat); EnterCriticalSection(&crit); stat.dwCurrentState = currentState; LeaveCriticalSection(&crit); return SetServiceStatus(statusHandle, &stat); } static VOID WINAPI handler(DWORD control){ char buffer[1024]; sprintf(buffer,"handler called with control = %d.",(int) control); log_debug(buffer); switch(control){ case SERVICE_CONTROL_STOP: set_stop_pending(30000,1); SetEvent(eventStop); return; case SERVICE_CONTROL_SHUTDOWN: return; default: reset_current(); break; } return; } typedef struct _server_info { RegEntry *keys; PROCESS_INFORMATION info; HANDLE erl_stdin; char *event_name; } ServerInfo; typedef struct { BOOL initialized; TOKEN_DEFAULT_DACL *defdacl; PACL newacl; PSID adminsid; } SaveAclStruct; static BOOL reset_acl(SaveAclStruct *save_acl){ HANDLE tokenh; if(!save_acl->initialized) return FALSE; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ|TOKEN_WRITE,&tokenh)){ log_warning("Failed to open access token."); return FALSE; } save_acl->initialized = FALSE; if(!SetTokenInformation(tokenh, TokenDefaultDacl, save_acl->defdacl, sizeof(TOKEN_DEFAULT_DACL))){ log_warning("Failed to get default ACL from token."); CloseHandle(tokenh); LocalFree(save_acl->defdacl); LocalFree(save_acl->newacl); FreeSid(save_acl->adminsid); return FALSE; } CloseHandle(tokenh); LocalFree(save_acl->defdacl); LocalFree(save_acl->newacl); FreeSid(save_acl->adminsid); return TRUE; } static BOOL new_acl(SaveAclStruct *save_acl){ HANDLE tokenh; TOKEN_DEFAULT_DACL newdacl; DWORD required; PACL oldacl; PACL newacl; int i; ACL_SIZE_INFORMATION si; size_t newsize; PSID extra_sid; SID_IDENTIFIER_AUTHORITY nt_auth = SECURITY_NT_AUTHORITY; TOKEN_DEFAULT_DACL dummy; save_acl->initialized = FALSE; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ|TOKEN_WRITE,&tokenh)){ log_warning("Failed to open access token."); return FALSE; } save_acl->defdacl = &dummy; required = sizeof(TOKEN_DEFAULT_DACL); GetTokenInformation(tokenh, TokenDefaultDacl, &(save_acl->defdacl), sizeof(TOKEN_DEFAULT_DACL), &required); if(required == 0){ log_warning("Failed to get any ACL info from token."); CloseHandle(tokenh); return FALSE; } save_acl->defdacl = LocalAlloc(LPTR,required); if(!GetTokenInformation(tokenh, TokenDefaultDacl, save_acl->defdacl, required, &required)){ #ifdef HARDDEBUG { char *mes; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &mes, 0, NULL ); log_info(mes); LocalFree(mes); } #endif log_warning("Failed to get default ACL from token."); CloseHandle(tokenh); return FALSE; } oldacl = save_acl->defdacl->DefaultDacl; if(!GetAclInformation(oldacl, &si, sizeof(si), AclSizeInformation)){ log_warning("Failed to get size information for ACL"); CloseHandle(tokenh); return FALSE; } if(!AllocateAndInitializeSid(&nt_auth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &extra_sid)){ log_warning("Failed to initialize administrator SID."); CloseHandle(tokenh); return FALSE; } newsize = si.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(extra_sid); newacl = LocalAlloc(LPTR,newsize); if(!InitializeAcl(newacl, newsize, ACL_REVISION)){ log_warning("Failed to initialize new ACL."); LocalFree(newacl); FreeSid(extra_sid); CloseHandle(tokenh); return FALSE; } for(i=0;i<((int)si.AceCount);++i){ ACE_HEADER *ace_header; if (!GetAce (oldacl, i, &ace_header)){ log_warning("Failed to get ACE from old ACL."); LocalFree(newacl); FreeSid(extra_sid); CloseHandle(tokenh); return FALSE; } if(!AddAce(newacl,ACL_REVISION,0xffffffff,ace_header, ace_header->AceSize)){ log_warning("Failed to set ACE in new ACL."); LocalFree(newacl); FreeSid(extra_sid); CloseHandle(tokenh); return FALSE; } } if(!AddAccessAllowedAce(newacl, ACL_REVISION2, PROCESS_ALL_ACCESS, extra_sid)){ log_warning("Failed to add system ACE to new ACL."); LocalFree(newacl); FreeSid(extra_sid); return FALSE; } newdacl.DefaultDacl = newacl; if(!SetTokenInformation(tokenh, TokenDefaultDacl, &newdacl, sizeof(newdacl))){ log_warning("Failed to set token information"); LocalFree(newacl); FreeSid(extra_sid); CloseHandle(tokenh); return FALSE; } save_acl->initialized = TRUE; save_acl->newacl = newacl; save_acl->adminsid = extra_sid; CloseHandle(tokenh); return TRUE; } static char **find_arg(char **arg, char *str){ char *tmp; int len; str = strdup(str); if((tmp = strchr(str,'=')) == NULL) goto fail; tmp++; *tmp = '\0'; len = tmp - str; while(*arg != NULL){ if(!_strnicmp(*arg,str,len)){ free(str); return arg; } ++arg; } fail: free(str); return NULL; } static char **merge_environment(char *current, char *add){ char **c_arg = env_to_arg(envdup(current)); char **a_arg = env_to_arg(envdup(add)); char **new; char **tmp; int i,j; for(i=0;c_arg[i] != NULL;++i) ; for(j=0;a_arg[j] != NULL;++j) ; new = malloc(sizeof(char *)*(i + j + 3)); for(i = 0; c_arg[i] != NULL; ++i) new[i] = strdup(c_arg[i]); new[i] = NULL; for(j = 0; a_arg[j] != NULL; ++j){ if((tmp = find_arg(new,a_arg[j])) != NULL){ free(*tmp); *tmp = strdup(a_arg[j]); } else { new[i++] = strdup(a_arg[j]); new[i] = NULL; } } free(arg_to_env(c_arg)); free(arg_to_env(a_arg)); return new; } static char *get_next_debug_file(char *prefix){ char *buffer = malloc(strlen(prefix)+12); int i; for(i=1;i<100;++i){ sprintf(buffer,"%s.%d",prefix,i); if(GetFileAttributes(buffer) == 0xFFFFFFFF) return buffer; } return NULL; } static BOOL start_a_service(ServerInfo *srvi){ STARTUPINFO start; char execbuff[MAX_PATH*4]; /* FIXME: Can get overflow! */ char namebuff[MAX_PATH]; char errbuff[MAX_PATH*4]; /* hmmm.... */ HANDLE write_pipe = NULL, read_pipe = NULL; SECURITY_ATTRIBUTES pipe_security; SECURITY_ATTRIBUTES attr; HANDLE nul; SaveAclStruct save_acl; char *my_environ; BOOL console_allocated = FALSE; if(!(*(srvi->keys[Env].data.bytes))){ my_environ = NULL; } else { char *tmp; char **merged = merge_environment((tmp = GetEnvironmentStrings()), srvi->keys[Env].data.bytes); FreeEnvironmentStrings(tmp); my_environ = arg_to_env(merged); } if(!*(srvi->keys[Machine].data.bytes) || (!*(srvi->keys[SName].data.bytes) && !*(srvi->keys[Name].data.bytes))){ log_error("Not enough parameters for erlang service."); if(my_environ) free(my_environ); return FALSE; } if(*(srvi->keys[SName].data.bytes)) sprintf(namebuff,"-nohup -sname %s",srvi->keys[SName].data.bytes); else sprintf(namebuff,"-nohup -name %s",srvi->keys[Name].data.bytes); if(srvi->keys[DebugType].data.value == DEBUG_TYPE_CONSOLE) strcat(namebuff," -keep_window"); if (srvi->event_name != NULL) { sprintf(execbuff,"\"%s\" -service_event %s %s %s", srvi->keys[Machine].data.bytes, srvi->event_name, namebuff, srvi->keys[Args].data.bytes); } else { sprintf(execbuff,"\"%s\" %s %s", srvi->keys[Machine].data.bytes, namebuff, srvi->keys[Args].data.bytes); } memset (&start, 0, sizeof (start)); start.cb = sizeof (start); start.dwFlags = STARTF_USESHOWWINDOW; start.wShowWindow = SW_HIDE; /* Console debugging implies no working StopAction */ if(srvi->keys[DebugType].data.value == DEBUG_TYPE_CONSOLE) { COORD coord = {80,999}; if(console_allocated = AllocConsole()) SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),coord); else log_warning("Unable to allocate debugging console!"); } else if(*(srvi->keys[StopAction].data.bytes) || srvi->keys[DebugType].data.value != DEBUG_TYPE_NO_DEBUG){ pipe_security.nLength = sizeof(pipe_security); pipe_security.lpSecurityDescriptor = NULL; pipe_security.bInheritHandle = TRUE; if(!CreatePipe(&read_pipe,&write_pipe,&pipe_security,0)){ log_error("Could not create pipe for erlang service."); if(my_environ) free(my_environ); return FALSE; } if(srvi->keys[DebugType].data.value != DEBUG_TYPE_NO_DEBUG){ char *filename; if(*(srvi->keys[WorkDir].data.bytes)){ filename = malloc(strlen(srvi->keys[WorkDir].data.bytes) + 1 + strlen(service_name)+strlen(".debug")+1); sprintf(filename,"%s\\%s.debug", srvi->keys[WorkDir].data.bytes, service_name); } else { filename = malloc(strlen(service_name)+strlen(".debug")+1); sprintf(filename,"%s.debug",service_name); } log_debug(filename); if(srvi->keys[DebugType].data.value == DEBUG_TYPE_NEW){ char *tmpfn = get_next_debug_file(filename); if(tmpfn){ free(filename); filename = tmpfn; } else { log_warning("Number of debug files exceeds system defined " "limit, reverting to DebugType: reuse. "); } } nul = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &pipe_security, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); free(filename); } else { /* Not debugging */ nul = CreateFile("NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &pipe_security, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } if(nul == NULL){ log_error((srvi->keys[DebugType].data.value != DEBUG_TYPE_NO_DEBUG) ? "Could not create debug file. " "(Working directory not valid?)" : "Cold not open NUL!"); start.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); start.hStdError = GetStdHandle(STD_ERROR_HANDLE); } start.hStdOutput = nul; start.hStdError = nul; start.hStdInput = read_pipe; start.dwFlags |= STARTF_USESTDHANDLES; } attr.nLength = sizeof(attr); attr.lpSecurityDescriptor = NULL; attr.bInheritHandle = TRUE; new_acl(&save_acl); if(!CreateProcess(NULL, execbuff, &attr, NULL, (read_pipe != NULL), CREATE_DEFAULT_ERROR_MODE | (srvi->keys[Priority].data.value), my_environ, (*(srvi->keys[WorkDir].data.bytes)) ? srvi->keys[WorkDir].data.bytes : NULL, &start, &(srvi->info))){ sprintf(errbuff,"Could not start erlang service " "with commandline \"%s\".", service_name, execbuff ); log_error(errbuff); if(read_pipe != NULL){ CloseHandle(read_pipe); CloseHandle(write_pipe); if(nul != NULL) CloseHandle(nul); } if(console_allocated) FreeConsole(); reset_acl(&save_acl); if(my_environ) free(my_environ); return FALSE; } if(console_allocated) FreeConsole(); #ifdef HARDDEBUG sprintf(errbuff, "Started %s with the following commandline: " "%s",service_name,execbuff); log_debug(errbuff); #endif if(read_pipe != NULL){ CloseHandle(read_pipe); if(nul != NULL) CloseHandle(nul); srvi->erl_stdin = write_pipe; } reset_acl(&save_acl); if(my_environ) free(my_environ); return TRUE; } static HANDLE create_erlang_event(char *event_name) { HANDLE e; if ((e = OpenEvent(EVENT_ALL_ACCESS,FALSE,event_name)) == NULL) { if ((e = CreateEvent(NULL, TRUE, FALSE, event_name)) == NULL) { log_warning("Could not create or access erlang termination event"); } } else { if (!ResetEvent(e)) { log_warning("Could not reset erlang termination event."); } } return e; } static BOOL stop_erlang(ServerInfo *srvi, int waithint, int *checkpoint){ DWORD written = 0; char *action = srvi->keys[StopAction].data.bytes; DWORD towrite = strlen(action)+1; char *toerl; DWORD exitcode; int i; int kill; if(towrite > 2 && srvi->erl_stdin != NULL){ toerl = malloc(towrite+1); strcpy(toerl,action); strcat(toerl,"\n"); WriteFile(srvi->erl_stdin, toerl, towrite, &written,0); free(toerl); /* Give it 45 seconds to terminate */ for(i=0;i<45;++i){ if(WaitForSingleObject(srvi->info.hProcess, 1000) == WAIT_OBJECT_0){ GetExitCodeProcess(srvi->info.hProcess,&exitcode); CloseHandle(srvi->info.hProcess); CloseHandle(srvi->info.hThread); return TRUE; } ++(*checkpoint); set_stop_pending(waithint,*checkpoint); } log_warning("StopAction did not terminate erlang. Trying forced kill."); } log_debug("Terminating erlang..."); kill = 1; if(eventKillErlang != NULL && SetEvent(eventKillErlang) != 0){ for(i=0;i<10;++i){ if(WaitForSingleObject(srvi->info.hProcess, 1000) == WAIT_OBJECT_0){ kill = 0; break; } ++(*checkpoint); set_stop_pending(waithint,*checkpoint); } } else { #ifdef HARDDEBUG { char *mes; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &mes, 0, NULL ); log_info(mes); LocalFree(mes); } #endif log_debug("Could not send control event to Erlang process"); } if(kill){ log_warning("Using TerminateProcess to kill erlang."); if(!TerminateProcess(srvi->info.hProcess,NO_ERROR)) log_error("TerminateProcess failed"); } GetExitCodeProcess(srvi->info.hProcess,&exitcode); CloseHandle(srvi->info.hProcess); CloseHandle(srvi->info.hThread); if (eventKillErlang != NULL) { ResetEvent(eventKillErlang); } return TRUE; } static BOOL enable_privilege(void) { HANDLE ProcessHandle; DWORD DesiredAccess = TOKEN_ADJUST_PRIVILEGES; HANDLE TokenHandle; TOKEN_PRIVILEGES Tpriv; LUID luid; ProcessHandle = GetCurrentProcess(); OpenProcessToken(ProcessHandle, DesiredAccess, &TokenHandle); LookupPrivilegeValue(0,SE_SHUTDOWN_NAME,&luid); Tpriv.PrivilegeCount = 1; Tpriv.Privileges[0].Luid = luid; Tpriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; return AdjustTokenPrivileges(TokenHandle,FALSE,&Tpriv,0,0,0); } static BOOL pull_service_name(void){ SC_HANDLE scm; DWORD sz = 1024; static char service_name_buff[1024]; if((scm = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL){ return FALSE; } if(!GetServiceDisplayName(scm,real_service_name,service_name_buff,&sz)) return FALSE; CloseServiceHandle(scm); service_name = service_name_buff; return TRUE; } static VOID WINAPI service_main_loop(DWORD argc, char **argv){ int waithint = 30000; int checkpoint = 1; RegEntry *keys; RegEntry *save_keys; ServerInfo srvi; HANDLE harr[2]; FILETIME creationt,exitt,kernelt,usert; LONGLONG creationl,exitl,diffl; char event_name[MAX_PATH] = "ErlSrv_"; char executable_name[MAX_PATH]; #ifdef DEBUG char errorbuff[2048]; /* FIXME... */ #endif int success_wait = NO_SUCCESS_WAIT; real_service_name = argv[0]; if(!pull_service_name()){ log_error("Could not get Display name of erlang service."); set_stopped(ERROR_CANTREAD); return; } SetEnvironmentVariable((LPCTSTR) SERVICE_ENV, (LPCTSTR) service_name); strncat(event_name, service_name, MAX_PATH - strlen(event_name)); event_name[MAX_PATH - 1] = '\0'; if(!GetModuleFileName(NULL, executable_name, MAX_PATH)){ log_error("Unable to retrieve module file name, " EXECUTABLE_ENV " will not be set."); } else { char quoted_exe_name[MAX_PATH+4]; sprintf(quoted_exe_name, "\"%s\"", executable_name); SetEnvironmentVariable((LPCTSTR) EXECUTABLE_ENV, (LPCTSTR) quoted_exe_name); } log_debug("Here we go, service_main_loop..."); currentState = SERVICE_START_PENDING; InitializeCriticalSection(&crit); eventStop = CreateEvent(NULL,FALSE,FALSE,NULL); if ((eventKillErlang = create_erlang_event(event_name)) != NULL) { srvi.event_name = event_name; } else { srvi.event_name = NULL; } statusHandle = RegisterServiceCtrlHandler(real_service_name, &handler); if(!statusHandle) return; set_start_pending(waithint,checkpoint); keys = get_keys(service_name); if(!keys){ log_error("Could not get registry keys for erlang service."); set_stopped(ERROR_CANTREAD); return; } srvi.keys = keys; srvi.erl_stdin = NULL; ++checkpoint; if(!start_a_service(&srvi)){ log_error("Could not start erlang machine"); set_stopped(ERROR_PROCESS_ABORTED); if (eventKillErlang != NULL) { CloseHandle(eventKillErlang); } free_keys(keys); return; } set_start_pending(waithint,checkpoint); set_running(); success_wait = INITIAL_SUCCESS_WAIT; harr[0] = srvi.info.hProcess; harr[1] = eventStop; for(;;){ DWORD ret; ret = WaitForMultipleObjects((DWORD) 2, harr, FALSE, (success_wait == NO_SUCCESS_WAIT) ? INFINITE : SUCCESS_WAIT_TIME); if(ret == WAIT_TIMEOUT){ /* Just do the "success reporting" and continue */ if(success_wait == INITIAL_SUCCESS_WAIT){ log_info("Erlang service started successfully."); } else { log_warning("Erlang service restarted"); } success_wait = NO_SUCCESS_WAIT; continue; } if(ret == WAIT_FAILED || (int)(ret-WAIT_OBJECT_0) >= 2){ set_stopped(WAIT_FAILED); log_error("Internal error, could not wait for objects."); if (eventKillErlang != NULL) { CloseHandle(eventKillErlang); } free_keys(keys); return; } ret -= WAIT_OBJECT_0; if(((int) ret) == 1){ /* Stop service... */ checkpoint = 2; /* 1 is taken by the handler */ set_stop_pending(waithint,checkpoint); if(stop_erlang(&srvi,waithint,&checkpoint)){ log_debug("Erlang machine is stopped"); CloseHandle(eventStop); if (eventKillErlang != NULL) { CloseHandle(eventKillErlang); } set_stopped(NO_ERROR); if(srvi.erl_stdin) CloseHandle(srvi.erl_stdin); free_keys(keys); return; } else { log_warning("Unable to stop erlang service."); set_running(); continue; } } /* Reload the registry keys, they may have changed. */ save_keys = keys; keys = get_keys(service_name); if(!keys){ log_error("Could not reload registry keys."); keys = srvi.keys = save_keys; } else { #ifdef HARDDEBUG sprintf(errorbuff,"Reloaded the registry keys because %s stopped.", service_name); log_debug(errorbuff); #endif /* HARDDEBUG */ free_keys(save_keys); srvi.keys = keys; } if(srvi.keys[OnFail].data.value == ON_FAIL_RESTART || srvi.keys[OnFail].data.value == ON_FAIL_RESTART_ALWAYS){ if(!GetProcessTimes(srvi.info.hProcess,&creationt, &exitt,&kernelt,&usert)){ DWORD rcode = GetLastError(); log_error("Could not get process time of terminated process."); CloseHandle(srvi.info.hProcess); CloseHandle(srvi.info.hThread); CloseHandle(eventStop); if(srvi.erl_stdin) CloseHandle(srvi.erl_stdin); set_stopped(rcode); if (eventKillErlang != NULL) { CloseHandle(eventKillErlang); } free_keys(keys); return; } CloseHandle(srvi.info.hProcess); CloseHandle(srvi.info.hThread); if(srvi.erl_stdin) CloseHandle(srvi.erl_stdin); srvi.erl_stdin = NULL; memcpy(&creationl,&creationt,sizeof(FILETIME)); memcpy(&exitl,&exitt,sizeof(FILETIME)); diffl = exitl - creationl; diffl /= 10000000; #ifdef DEBUG sprintf(errorbuff,"Process lived for %d seconds", (int) diffl); log_debug(errorbuff); #endif if(diffl > CYCLIC_RESTART_LIMIT || srvi.keys[OnFail].data.value == ON_FAIL_RESTART_ALWAYS){ if(!start_a_service(&srvi)){ log_error("Unable to restart failed erlang service, " "aborting."); CloseHandle(eventStop); set_stopped(ERROR_PROCESS_ABORTED); if (eventKillErlang != NULL) { CloseHandle(eventKillErlang); } free_keys(keys); return; } log_warning("Restarted erlang machine."); if(diffl <= CYCLIC_RESTART_LIMIT) log_warning("Possible cyclic restarting of erlang machine."); success_wait = RESTART_SUCCESS_WAIT; harr[0] = srvi.info.hProcess; } else { if(success_wait == INITIAL_SUCCESS_WAIT){ log_error("Erlang machine stopped instantly " "(distribution name conflict?). " "The service is not restarted, ignoring OnFail option."); } else { log_error("Erlang machine seems to die " "continously, not restarted."); } CloseHandle(eventStop); set_stopped(ERROR_PROCESS_ABORTED); if (eventKillErlang != NULL) { CloseHandle(eventKillErlang); } free_keys(keys); return; } } else if(srvi.keys[OnFail].data.value == ON_FAIL_REBOOT){ log_error("Rebooting because erlang machine stopped."); enable_privilege(); if(!InitiateSystemShutdown("",NULL,0,TRUE,TRUE)){ log_error("Failed to reboot!"); #ifdef HARDDEBUG { char *mes; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &mes, 0, NULL ); log_debug(mes); LocalFree(mes); } #endif CloseHandle(srvi.info.hProcess); CloseHandle(eventStop); if(srvi.erl_stdin != NULL) CloseHandle(srvi.erl_stdin); set_stopped(NO_ERROR); if (eventKillErlang != NULL) { CloseHandle(eventKillErlang); } free_keys(keys); return; } } else { DWORD ecode = NO_ERROR; if(success_wait == NO_SUCCESS_WAIT){ log_warning("Erlang machine voluntarily stopped. " "The service is not restarted as OnFail " "is set to ignore."); } else { log_error("Erlang machine stopped instantly " "(distribution name conflict?). " "The service is not restarted as OnFail is set to ignore."); ecode = ERROR_PROCESS_ABORTED; } CloseHandle(srvi.info.hProcess); CloseHandle(eventStop); if(srvi.erl_stdin != NULL) CloseHandle(srvi.erl_stdin); set_stopped(ecode); if (eventKillErlang != NULL) { CloseHandle(eventKillErlang); } free_keys(keys); return; } } } int service_main(int argc, char **argv){ char dummy_name[] = ""; SERVICE_TABLE_ENTRY serviceTable[] = { { dummy_name, (LPSERVICE_MAIN_FUNCTION) service_main_loop}, { NULL, NULL } }; BOOL success; success = StartServiceCtrlDispatcher(serviceTable); if (!success) log_error("Could not initiate service"); log_debug("service_main done its job"); return 0; }