void CNTL_shutdown_service(const TEXT* message) { /************************************** * * C N T L _ s h u t d o w n _ s e r v i c e * ************************************** * * Functional description * **************************************/ const char* strings[2]; char buffer[BUFFER_SMALL]; sprintf(buffer, "%s error: %lu", service_name->c_str(), GetLastError()); HANDLE event_source = RegisterEventSource(NULL, service_name->c_str()); if (event_source) { strings[0] = buffer; strings[1] = message; ReportEvent(event_source, EVENTLOG_ERROR_TYPE, 0, 0, NULL, 2, 0, strings, NULL); DeregisterEventSource(event_source); } if (stop_event_handle) SetEvent(stop_event_handle); }
void WINAPI CNTL_main_thread( DWORD /*argc*/, char* /*argv*/[]) { /************************************** * * C N T L _ m a i n _ t h r e a d * ************************************** * * Functional description * **************************************/ service_handle = RegisterServiceCtrlHandler(service_name->c_str(), control_thread); if (!service_handle) return; // start everything, and wait here for ever, or at // least until we get the stop event indicating that // the service is stoping. bool failure = true; DWORD temp = 0; if (report_status(SERVICE_START_PENDING, NO_ERROR, 1, 3000) && (stop_event_handle = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL && report_status(SERVICE_START_PENDING, NO_ERROR, 2, 3000) && !gds__thread_start(main_handler, NULL, 0, 0, 0) && report_status(SERVICE_RUNNING, NO_ERROR, 0, 0)) { failure = false; temp = WaitForSingleObject(stop_event_handle, INFINITE); } DWORD last_error = 0; if (failure || temp == WAIT_FAILED) last_error = GetLastError(); if (stop_event_handle) CloseHandle(stop_event_handle); // Once we are stopped, we will tell the server to // do the same. We could not do this in the control_thread // since the Services Control Manager is single threaded, // and thus can only process one request at the time. SERVICE_STATUS status_info; SC_HANDLE hScManager = 0, hService = 0; hScManager = OpenSCManager(NULL, NULL, GENERIC_READ); hService = OpenService(hScManager, remote_name->c_str(), GENERIC_READ | GENERIC_EXECUTE); ControlService(hService, SERVICE_CONTROL_STOP, &status_info); CloseServiceHandle(hScManager); CloseServiceHandle(hService); report_status(SERVICE_STOPPED, last_error, 0, 0); }
const char *Config::getUdfAccess() { static Firebird::GlobalPtr<Firebird::Mutex> udfMutex; static Firebird::GlobalPtr<Firebird::string> udfValue; static const char* volatile value = 0; if (value) { return value; } Firebird::MutexLockGuard guard(udfMutex, "Config::getUdfAccess"); if (value) { return value; } const char* v = (const char*) getDefaultConfig()->values[KEY_UDF_ACCESS]; if (CASE_SENSITIVITY ? (! strcmp(v, UDF_DEFAULT_CONFIG_VALUE) && FB_UDFDIR[0]) : (! fb_utils::stricmp(v, UDF_DEFAULT_CONFIG_VALUE) && FB_UDFDIR[0])) { udfValue->printf("Restrict %s", FB_UDFDIR); value = udfValue->c_str(); } else { value = v; } return value; }
void WINAPI CNTL_main_thread( DWORD /*argc*/, char* /*argv*/[]) { /************************************** * * C N T L _ m a i n _ t h r e a d * ************************************** * * Functional description * **************************************/ service_handle = RegisterServiceCtrlHandler(service_name->c_str(), control_thread); if (!service_handle) return; int status = 1; DWORD temp = 0; if (report_status(SERVICE_START_PENDING, NO_ERROR, 1, 3000) && (stop_event_handle = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL && report_status(SERVICE_START_PENDING, NO_ERROR, 2, 3000)) { try { Thread::start(main_handler, NULL, THREAD_medium); if (report_status(SERVICE_RUNNING, NO_ERROR, 0, 0)) { status = 0; temp = WaitForSingleObject(stop_event_handle, INFINITE); } } catch (const Firebird::Exception& ex) { iscLogException("CNTL: cannot start service handler thread", ex); } } DWORD last_error = 0; if (temp == WAIT_FAILED || status) last_error = GetLastError(); if (stop_event_handle) CloseHandle(stop_event_handle); report_status(SERVICE_STOP_PENDING, NO_ERROR, 1, SHUTDOWN_TIMEOUT); fb_shutdown(SHUTDOWN_TIMEOUT, fb_shutrsn_svc_stopped); report_status(SERVICE_STOPPED, last_error, 0, 0); }
void CNTL_stop_service() //const TEXT* service) // unused param { /************************************** * * C N T L _ s t o p _ s e r v i c e * ************************************** * * Functional description * This function is called to stop the service. * * **************************************/ SC_HANDLE servicemgr_handle = OpenSCManager(NULL, NULL, GENERIC_READ); if (servicemgr_handle == NULL) { // return error int error = GetLastError(); gds__log("SC manager error %d", error); return; } SC_HANDLE service_handleL = OpenService(servicemgr_handle, service_name->c_str(), GENERIC_READ | GENERIC_EXECUTE); if (service_handleL == NULL) { // return error int error = GetLastError(); gds__log("open services error %d", error); return; } else { SERVICE_STATUS status_info; if (!ControlService (service_handleL, SERVICE_CONTROL_STOP, &status_info)) { // return error const int error = GetLastError(); gds__log("Control services error %d", error); return; } } }
static void WINAPI control_thread( DWORD action) { /************************************** * * c o n t r o l _ t h r e a d * ************************************** * * Functional description * Process a service control request. * **************************************/ const DWORD state = SERVICE_RUNNING; switch (action) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: report_status(SERVICE_STOP_PENDING, NO_ERROR, 1, 3000); if (hMutex) ReleaseMutex(hMutex); SetEvent(stop_event_handle); return; case SERVICE_CONTROL_INTERROGATE: break; case SERVICE_CREATE_GUARDIAN_MUTEX: hMutex = OpenMutex(SYNCHRONIZE, FALSE, mutex_name->c_str()); if (hMutex) { UINT error_mode = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX | SEM_NOALIGNMENTFAULTEXCEPT; SetErrorMode(error_mode); WaitForSingleObject(hMutex, INFINITE); } break; default: break; } report_status(state, NO_ERROR, 0, 0); }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR lpszCmdLine, int /*nCmdShow*/) { /************************************** * * m a i n * ************************************** * * Functional description * The main routine for Windows based server guardian. * **************************************/ strcpy(instance, FB_DEFAULT_INSTANCE); service_flag = parse_args(lpszCmdLine); service_name->printf(ISCGUARD_SERVICE, instance); remote_name->printf(REMOTE_SERVICE, instance); mutex_name->printf(GUARDIAN_MUTEX, instance); // set the global HINSTANCE as we need it in WINDOW_main hInstance_gbl = hInstance; // allocate space for the event list log_entry = static_cast<log_info*>(malloc(sizeof(log_info))); log_entry->next = NULL; // since the flag is set we run as a service if (service_flag) { CNTL_init(WINDOW_main, instance); const SERVICE_TABLE_ENTRY service_table[] = { {const_cast<char*>(service_name->c_str()), CNTL_main_thread}, {NULL, NULL} }; // BRS There is a error in MinGW (3.1.0) headers // the parameter of StartServiceCtrlDispatcher is declared const in msvc headers #if defined(MINGW) if (!StartServiceCtrlDispatcher(const_cast<SERVICE_TABLE_ENTRY*>(service_table))) #else if (!StartServiceCtrlDispatcher(service_table)) #endif { if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) CNTL_shutdown_service("StartServiceCtrlDispatcher failed"); } if (watcher_thd) { WaitForSingleObject(watcher_thd, 5000); CloseHandle(watcher_thd); } } else { return WINDOW_main(0); } return TRUE; }
THREAD_ENTRY_DECLARE start_and_watch_server(THREAD_ENTRY_PARAM) { /************************************** * * s t a r t _ a n d _ w a t c h _ s e r v e r * ************************************** * * Functional description * * This function is where the server process is created and * the thread waits for this process to exit. * **************************************/ Firebird::ContextPoolHolder threadContext(getDefaultMemoryPool()); HANDLE procHandle = NULL; bool done = true; const UINT error_mode = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX | SEM_NOALIGNMENTFAULTEXCEPT; SC_HANDLE hScManager = 0, hService = 0; // get the guardian startup information const short option = Config::getGuardianOption(); char prefix_buffer[MAXPATHLEN]; GetModuleFileName(NULL, prefix_buffer, sizeof(prefix_buffer)); Firebird::PathName path = prefix_buffer; path = path.substr(0, path.rfind(PathUtils::dir_sep) + 1) + FBSERVER; path = "\"" + path + "\""; Firebird::PathName prog_name = path + " -a -n"; // if the guardian is set to FOREVER then set the error mode UINT old_error_mode = 0; if (option == START_FOREVER) old_error_mode = SetErrorMode(error_mode); // Spawn the new process do { SERVICE_STATUS ServiceStatus; char out_buf[1024]; BOOL success; int error = 0; if (service_flag) { if (hService) { while ((QueryServiceStatus(hService, &ServiceStatus) == TRUE) && (ServiceStatus.dwCurrentState != SERVICE_STOPPED)) { Sleep(500); } } procHandle = CreateMutex(NULL, FALSE, mutex_name->c_str()); // start as a service. If the service can not be found or // fails to start, close the handle to the mutex and set // success = FALSE if (!hScManager) hScManager = OpenSCManager(NULL, NULL, GENERIC_READ); if (!hService) { hService = OpenService(hScManager, remote_name->c_str(), GENERIC_READ | GENERIC_EXECUTE); } success = StartService(hService, 0, NULL); if (success != TRUE) error = GetLastError(); // if the server is already running, then inform it that it should // open the guardian mutex so that it may be governed. if (!error || error == ERROR_SERVICE_ALREADY_RUNNING) { // Make sure that it is actually ready to receive commands. // If we were the one who started it, then it will need a few // seconds to get ready. while ((QueryServiceStatus(hService, &ServiceStatus) == TRUE) && (ServiceStatus.dwCurrentState != SERVICE_RUNNING)) { Sleep(500); } ControlService(hService, SERVICE_CREATE_GUARDIAN_MUTEX, &ServiceStatus); success = TRUE; } } else { HWND hTmpWnd = FindWindow(szClassName, szWindowName); if (hTmpWnd == NULL) { STARTUPINFO si; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; success = CreateProcess(NULL, const_cast<char*>(prog_name.c_str()), &sa, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (success != TRUE) error = GetLastError(); procHandle = pi.hProcess; // TMN: 04 Aug 2000 - closed the handle that previously leaked. CloseHandle(pi.hThread); } else { SendMessage(hTmpWnd, WM_COMMAND, (WPARAM) IDM_GUARDED, 0); DWORD server_pid; GetWindowThreadProcessId(hTmpWnd, &server_pid); procHandle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, server_pid); if (procHandle == NULL) { error = GetLastError(); success = FALSE; } else { success = TRUE; } } } if (success != TRUE) { // error creating new process char szMsgString[256]; LoadString(hInstance_gbl, IDS_CANT_START_THREAD, szMsgString, 256); sprintf(out_buf, "%s : %s errno : %d", path.c_str(), szMsgString, error); write_log(IDS_CANT_START_THREAD, out_buf); if (service_flag) { SERVICE_STATUS status_info; // wait a second to get the mutex handle (just in case) and // then close it WaitForSingleObject(procHandle, 1000); CloseHandle(procHandle); hService = OpenService(hScManager, remote_name->c_str(), GENERIC_READ | GENERIC_EXECUTE); ControlService(hService, SERVICE_CONTROL_STOP, &status_info); CloseServiceHandle(hScManager); CloseServiceHandle(hService); CNTL_stop_service(); //service_name->c_str()); } else { MessageBox(NULL, out_buf, NULL, MB_OK | MB_ICONSTOP); PostMessage(hWndGbl, WM_CLOSE, 0, 0); } return 0; } else { char szMsgString[256]; LoadString(hInstance_gbl, IDS_STARTING_GUARD, szMsgString, 256); sprintf(out_buf, "%s: %s\n", szMsgString, path.c_str()); write_log(IDS_LOG_START, out_buf); } // wait for process to terminate DWORD exit_status; if (service_flag) { while (WaitForSingleObject(procHandle, 500) == WAIT_OBJECT_0) { ReleaseMutex(procHandle); Sleep(100); } const int ret_val = WaitForSingleObject(procHandle, INFINITE); if (ret_val == WAIT_ABANDONED) exit_status = CRASHED; else if (ret_val == WAIT_OBJECT_0) exit_status = NORMAL_EXIT; CloseHandle(procHandle); } else { while (WaitForSingleObject(procHandle, INFINITE) == WAIT_FAILED) ; GetExitCodeProcess(procHandle, &exit_status); CloseHandle(procHandle); } if (exit_status != NORMAL_EXIT) { // check for startup error if (exit_status == STARTUP_ERROR) { char szMsgString[256]; LoadString(hInstance_gbl, IDS_STARTUP_ERROR, szMsgString, 256); sprintf(out_buf, "%s: %s (%lu)\n", path.c_str(), szMsgString, exit_status); write_log(IDS_STARTUP_ERROR, out_buf); done = true; } else { char szMsgString[256]; LoadString(hInstance_gbl, IDS_ABNORMAL_TERM, szMsgString, 256); sprintf(out_buf, "%s: %s (%lu)\n", path.c_str(), szMsgString, exit_status); write_log(IDS_LOG_TERM, out_buf); // switch the icons if the server restarted if (!service_flag) PostMessage(hWndGbl, WM_SWITCHICONS, 0, 0); if (option == START_FOREVER) done = false; } } else { // Normal shutdown - ie: via ibmgr - don't restart the server char szMsgString[256]; LoadString(hInstance_gbl, IDS_NORMAL_TERM, szMsgString, 256); sprintf(out_buf, "%s: %s\n", path.c_str(), szMsgString); write_log(IDS_LOG_STOP, out_buf); done = true; } if (option == START_ONCE) done = true; } while (!done); // If on WINNT if (service_flag) { CloseServiceHandle(hScManager); CloseServiceHandle(hService); CNTL_stop_service(); //(service_name->c_str()); } else PostMessage(hWndGbl, WM_CLOSE, 0, 0); return 0; }
static void write_log(int log_action, const char* buff) { /****************************************************************************** * * w r i t e _ l o g * ****************************************************************************** * * Description: Writes the guardian information to either the Windows 95 * property sheet structure (log_entry) or to the Windows NT * Event Log *****************************************************************************/ const size_t BUFF_SIZE = 512; char tmp_buff[BUFF_SIZE]; // Move to the end of the log_entry list log_info* log_temp = log_entry; while (log_temp->next) log_temp = log_temp->next; log_info* tmp = static_cast<log_info*>(malloc(sizeof(log_info))); memset(tmp, 0, sizeof(log_info)); #ifdef NOT_USED_OR_REPLACED time_t ltime; time(<ime); const tm* today = localtime(<ime); sprintf(tmp->log_time, "%02d:%02d", today->tm_hour, today->tm_min); sprintf(tmp->log_date, "%02d/%02d/%02d", today->tm_mon + 1, today->tm_mday, today->tm_year % 100); #else // TMN: Fixed this after bug-report. Should it really force // 24hr format in e.g US, where they use AM/PM wharts? GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS | TIME_FORCE24HOURFORMAT, NULL, NULL, tmp->log_time, sizeof(tmp->log_time)); GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, tmp->log_date, sizeof(tmp->log_date)); #endif if (log_action >= IDS_LOG_START && log_action <= IDS_LOG_TERM) { // Only Windows 95 needs this information since it goes in the property sheet LoadString(hInstance_gbl, log_action, tmp_buff, sizeof(tmp->log_action)); sprintf(tmp->log_action, "%s", tmp_buff); tmp->next = NULL; log_temp->next = tmp; } if (service_flag) { // on NT HANDLE hLog = RegisterEventSource(NULL, service_name->c_str()); if (!hLog) gds__log("Error opening Windows NT Event Log"); else { char buffer[BUFF_SIZE]; char* act_buff[1]; act_buff[0] = buffer; LoadString(hInstance_gbl, log_action + 1, tmp_buff, sizeof(tmp_buff)); sprintf(act_buff[0], "%s", buff); LPTSTR lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING, tmp_buff, 0, 0, (LPTSTR) &lpMsgBuf, 0, reinterpret_cast<va_list*>(act_buff)); const int len = MIN(BUFF_SIZE - 1, strlen(lpMsgBuf) - 1); strncpy(act_buff[0], lpMsgBuf, len); act_buff[0][len] = 0; LocalFree(lpMsgBuf); WORD wLogType; switch (log_action) { case IDS_LOG_START: case IDS_LOG_STOP: wLogType = EVENTLOG_INFORMATION_TYPE; break; default: wLogType = EVENTLOG_ERROR_TYPE; } if (!ReportEvent (hLog, wLogType, 0, log_action + 1, NULL, 1, 0, const_cast<const char**>(act_buff), NULL)) { FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) & lpMsgBuf, 0, NULL); gds__log("Unable to update NT Event Log.\n\tOS Message: %s", lpMsgBuf); LocalFree(lpMsgBuf); } DeregisterEventSource(hLog); } } // Write to the Firebird log if (*buff) gds__log(buff); }