Example #1
0
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);
}
Example #2
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;
}
Example #3
0
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);
}
Example #4
0
int ISC_kill(SLONG pid, SLONG signal_number, void *object_hndl)
{
/**************************************
 *
 *	I S C _ k i l l		( W I N _ N T )
 *
 **************************************
 *
 * Functional description
 *	Notify somebody else.
 *
 **************************************/

	// If we're simply trying to poke ourselves, do so directly.
	ISC_signal_init();

	if (pid == process_id)
		return SetEvent(object_hndl) ? 0 : -1;

	HANDLE handle = openEvents->getEvent(pid, signal_number);
	if (!handle)
		return -1;

	return SetEvent(handle) ? 0 : -1;
}
Example #5
0
void CNTL_init(ThreadEntryPoint* handler, const TEXT* name)
{
/**************************************
 *
 *	C N T L _ i n i t
 *
 **************************************
 *
 * Functional description
 *
 **************************************/

	main_handler = handler;
	service_name->printf(REMOTE_SERVICE, name);
	mutex_name->printf(GUARDIAN_MUTEX, name);
}
Example #6
0
void CNTL_init(ThreadEntryPoint* handler, const TEXT* name)
{
/**************************************
 *
 *	C N T L _ i n i t
 *
 **************************************
 *
 * Functional description
 *
 **************************************/

	main_handler = handler;
	//MemoryPool& pool = *getDefaultMemoryPool();
	service_name->printf(ISCGUARD_SERVICE, name);
	remote_name->printf(REMOTE_SERVICE, name);
}
Example #7
0
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);
}
Example #8
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;
		}
	}
}
Example #9
0
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(&ltime);
	const tm* today = localtime(&ltime);

	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);
}