Beispiel #1
0
bool PathUtils::isSymLink(const Firebird::PathName& path)
{
	struct stat st, lst;
	if (stat(path.c_str(), &st) != 0)
		return false;
	if (lstat(path.c_str(), &lst) != 0)
		return false;
	return st.st_ino != lst.st_ino;
}
Beispiel #2
0
pid_t UTIL_start_process(const char* process, const char* process2, char** argv, const char* prog_name)
{
/**************************************
 *
 *      U T I L _ s t a r t _ p r o c e s s
 *
 **************************************
 *
 * Functional description
 *
 *     This function is used to create the specified process,
 *
 * Returns Codes:
 *	-1		Process spawn failed.
 *	pid		Successful creation. PID is returned.
 *
 *     Note: Make sure that the argument list ends with a null
 *     and the first argument is large enough to hold the complete
 *     expanded process name. (MAXPATHLEN recommended)
 *
 **************************************/
	fb_assert(process != NULL);
	fb_assert(argv != NULL);

	// prepend Firebird home directory to the program name
	// choose correct (super/superclassic) image - to be removed in 3.0
	Firebird::PathName string = fb_utils::getPrefix(fb_utils::FB_DIR_SBIN, process);
	if (access(string.c_str(), X_OK) < 0) {
		string = fb_utils::getPrefix(fb_utils::FB_DIR_SBIN, process2);
	}
	if (prog_name) {
		gds__log("%s: guardian starting %s\n", prog_name, string.c_str());
	}

	// add place in argv for visibility to "ps"
	strcpy(argv[0], string.c_str());
#if (defined SOLARIS)
	pid_t pid = fork1();
	if (!pid)
	{
		if (execv(string.c_str(), argv) == -1) {
			//ib_fprintf(ib_stderr, "Could not create child process %s with args %s\n", string, argv);
		}
		exit(FINI_ERROR);
	}

#else

	pid_t pid = vfork();
	if (!pid)
	{
		execv(string.c_str(), argv);
		_exit(FINI_ERROR);
	}
#endif
	return (pid);
}
Beispiel #3
0
bool ModuleLoader::isLoadableModule(const Firebird::PathName& module)
{
	struct stat sb;
	if (-1 == stat(module.c_str(), &sb))
		return false;
	if ( ! (sb.st_mode & S_IFREG) )		// Make sure it is a plain file
		return false;
	if ( -1 == access(module.c_str(), R_OK | X_OK))
		return false;
	return true;
}
Beispiel #4
0
// Probably file arrived on the disk
bool notifyDatabaseName(const Firebird::PathName& file)
{
#ifdef HAVE_ID_BY_NAME
	// notifyDatabaseName typically causes changes in aliasesConf()
	// cause it's called only from Config created for missing database.
	// Therefore always take write lock at once.
	WriteLockGuard guard(aliasesConf().rwLock, "notifyDatabaseName");

	DbName* db = aliasesConf().dbHash.lookup(file);
	if (!db)
		return true;
	if (db->id)
		return true;

	UCharBuffer id;
	os_utils::getUniqueFileId(file.c_str(), id);
	if (id.hasData())
	{
		aliasesConf().linkId(db, id);
		return true;
	}
#endif

	return false;
}
Beispiel #5
0
void LEX_init( void *file)
{
/**************************************
 *
 *	L E X _ i n i t
 *
 **************************************
 *
 * Functional description
 *	Initialize for lexical scanning.  While we're at it, open a
 *	scratch trace file to keep all input.
 *
 **************************************/
	const Firebird::PathName filename = Firebird::TempFile::create(SCRATCH);
	strcpy(trace_file_name, filename.c_str());
	trace_file = fopen(trace_file_name, "w+b");
	if (!trace_file)
	{
		DDL_err(276);
		/* msg 276: couldn't open scratch file */
	}

	input_file = (FILE*) file;
	DDL_char = DDL_buffer;
	dudleyGlob.DDL_token.tok_position = 0;
	dudleyGlob.DDL_description = false;
	dudleyGlob.DDL_line = 1;
}
Beispiel #6
0
// moves DB path information (from limbo transaction) to another buffer
void getDbPathInfo(unsigned int& itemsLength, const unsigned char*& items,
	unsigned int& bufferLength, unsigned char*& buffer,
	Firebird::Array<unsigned char>& newItemsBuffer, const Firebird::PathName& dbpath)
{
	if (itemsLength && items)
	{
		const unsigned char* ptr = (const unsigned char*) memchr(items, fb_info_tra_dbpath, itemsLength);
		if (ptr)
		{
			newItemsBuffer.add(items, itemsLength);
			newItemsBuffer.remove(ptr - items);
			items = newItemsBuffer.begin();
			--itemsLength;

			unsigned int len = dbpath.length();
			if (len + 3 > bufferLength)
			{
				len = bufferLength - 3;
			}
			bufferLength -= (len + 3);
			*buffer++ = fb_info_tra_dbpath;
			*buffer++ = len;
			*buffer++ = len >> 8;
			memcpy(buffer, dbpath.c_str(), len);
			buffer += len;
		}
	}
}
Beispiel #7
0
bool FileObject::renameFile(const Firebird::PathName new_filename)
{
	if (append_mutex != INVALID_HANDLE_VALUE)
	{
		if (WaitForSingleObject(append_mutex, INFINITE) != WAIT_OBJECT_0)
			system_call_failed::raise("WaitForSingleObject");
	}

	if (!MoveFile(filename.c_str(), new_filename.c_str()))
	{
		DWORD rename_err = GetLastError();
		if (rename_err == ERROR_ALREADY_EXISTS || rename_err == ERROR_FILE_NOT_FOUND)
		{
			// Another process renames our file just now. Open it again.
			reopen();
			return false;
		}

		if (append_mutex != INVALID_HANDLE_VALUE)
			ReleaseMutex(append_mutex);

		fatal_exception::raiseFmt("IO error (%d) renaming file: %s",
			rename_err,
			filename.c_str());
	}
	else
		reopen();

	return true;
}
Beispiel #8
0
void LEX_init()
{
/**************************************
 *
 *	L E X _ i n i t
 *
 **************************************
 *
 * Functional description
 *	Initialize for lexical scanning.  While we're at it, open a
 *	scratch trace file to keep all input.
 *
 **************************************/
	const Firebird::PathName filename = TempFile::create(SCRATCH);
	strcpy(trace_file_name, filename.c_str());
	trace_file = fopen(trace_file_name, "w+b");
#ifdef UNIX
	unlink(trace_file_name);
#endif
	if (!trace_file)
		IBERROR(61);			// Msg 61 couldn't open scratch file

	QLI_token = (qli_tok*) ALLOCPV(type_tok, MAXSYMLEN);

	QLI_line = (qli_line*) ALLOCPV(type_line, 0);
	QLI_line->line_size = sizeof(QLI_line->line_data);
	QLI_line->line_ptr = QLI_line->line_data;
	QLI_line->line_type = line_stdin;
	QLI_line->line_source_file = stdin;

	QLI_semi = false;
	input_file = stdin;
	HSH_init();
}
Beispiel #9
0
void ClntAuthBlock::extractDataFromPluginTo(Firebird::ClumpletWriter& user_id)
{
	// Add user login name
	if (cliOrigUserName.hasData())
	{
		HANDSHAKE_DEBUG(fprintf(stderr, "Cli: extractDataFromPluginTo: cliOrigUserName=%s\n",
			cliOrigUserName.c_str()));
		user_id.insertString(CNCT_login, cliOrigUserName);
	}

	// Add plugin name
	Firebird::PathName pluginName = getPluginName();
	if (pluginName.hasData())
	{
		HANDSHAKE_DEBUG(fprintf(stderr, "Cli: extractDataFromPluginTo: pluginName=%s\n", pluginName.c_str()));
		user_id.insertPath(CNCT_plugin_name, pluginName);
	}

	// Add plugin list
	if (pluginList.hasData())
	{
		user_id.insertPath(CNCT_plugin_list, pluginList);
	}

	// This is specially tricky field - user_id is limited to 255 bytes per entry,
	// and we have no ways to override this limit cause it can be sent to any version server.
	// Therefore divide data into 254-byte parts, leaving first byte for the number of that part.
	// This appears more reliable than put them in strict order.
	addMultiPartConnectParameter(dataFromPlugin, user_id, CNCT_specific_data);

	// Client's wirecrypt requested level
	user_id.insertInt(CNCT_client_crypt, clntConfig->getWireCrypt(WC_CLIENT));
}
Beispiel #10
0
void LEX_edit(SLONG start, SLONG stop)
{
/**************************************
 *
 *	L E X _ e d i t
 *
 **************************************
 *
 * Functional description
 *	Dump the last full statement into a scratch file, then
 *	push the scratch file on the input stack.
 *
 **************************************/
	const Firebird::PathName filename = TempFile::create(SCRATCH);
	FILE* scratch = fopen(filename.c_str(), "w+b");
	if (!scratch)
		IBERROR(61);			// Msg 61 couldn't open scratch file

#ifdef WIN_NT
	stop--;
#endif

	if (fseek(trace_file, start, 0))
	{
		fseek(trace_file, 0, 2);
		IBERROR(59);			// Msg 59 fseek failed
	}

	while (++start <= stop)
	{
		const SSHORT c = getc(trace_file);
		if (c == EOF)
			break;
		putc(c, scratch);
	}

	fclose(scratch);

	if (gds__edit(filename.c_str(), TRUE))
		LEX_push_file(filename.c_str(), true);

	unlink(filename.c_str());

	fseek(trace_file, 0, 2);
}
Beispiel #11
0
ConfigFile::ConfigFile(MemoryPool& p, const Firebird::PathName& file, USHORT fl, ConfigCache* cache)
	: AutoStorage(p),
	  parameters(getPool()),
	  flags(fl),
	  includeLimit(0),
	  filesCache(cache)
{
	MainStream s(file.c_str(), flags & ERROR_WHEN_MISS);
	parse(&s);
}
Beispiel #12
0
inline void setPrefixIfNotEmpty(const Firebird::PathName& prefix, SSHORT arg_type)
{
/**************************************
 *
 *         s e t P r e f i x I f N o t E m p t y
 *
 **************************************
 *
 * Functional description
 *      Helper for ISC_set_prefix
 *
 **************************************/
	if (prefix.hasData())
	{
		// ignore here return value of gds__get_prefix():
		// it will never fail with our good arguments
		gds__get_prefix(arg_type, prefix.c_str());
	}
}
Beispiel #13
0
// Build full file name in specified directory
Firebird::PathName getPrefix(unsigned int prefType, const char* name)
{
	Firebird::PathName s;
	char tmp[MAXPATHLEN];

	const char* configDir[] = {
		FB_BINDIR, FB_SBINDIR, FB_CONFDIR, FB_LIBDIR, FB_INCDIR, FB_DOCDIR, FB_UDFDIR, FB_SAMPLEDIR,
		FB_SAMPLEDBDIR, FB_HELPDIR, FB_INTLDIR, FB_MISCDIR, FB_SECDBDIR, FB_MSGDIR, FB_LOGDIR,
		FB_GUARDDIR, FB_PLUGDIR
	};

	fb_assert(FB_NELEM(configDir) == Firebird::IConfigManager::DIR_COUNT);
	fb_assert(prefType < Firebird::IConfigManager::DIR_COUNT);

	if (! bootBuild())
	{
		if (prefType != Firebird::IConfigManager::DIR_CONF &&
			prefType != Firebird::IConfigManager::DIR_MSG &&
			configDir[prefType][0])
		{
			// Value is set explicitly and is not environment overridable
			PathUtils::concatPath(s, configDir[prefType], name);
			return s;
		}
	}

	switch(prefType)
	{
		case Firebird::IConfigManager::DIR_BIN:
		case Firebird::IConfigManager::DIR_SBIN:
#ifdef WIN_NT
			s = "";
#else
			s = "bin";
#endif
			break;

		case Firebird::IConfigManager::DIR_CONF:
		case Firebird::IConfigManager::DIR_LOG:
		case Firebird::IConfigManager::DIR_GUARD:
		case Firebird::IConfigManager::DIR_SECDB:
			s = "";
			break;

		case Firebird::IConfigManager::DIR_LIB:
#ifdef WIN_NT
			s = "";
#else
			s = "lib";
#endif
			break;

		case Firebird::IConfigManager::DIR_PLUGINS:
			s = "plugins";
			break;

		case Firebird::IConfigManager::DIR_INC:
			s = "include";
			break;

		case Firebird::IConfigManager::DIR_DOC:
			s = "doc";
			break;

		case Firebird::IConfigManager::DIR_UDF:
			s = "UDF";
			break;

		case Firebird::IConfigManager::DIR_SAMPLE:
			s = "examples";
			break;

		case Firebird::IConfigManager::DIR_SAMPLEDB:
			s = "examples/empbuild";
			break;

		case Firebird::IConfigManager::DIR_HELP:
			s = "help";
			break;

		case Firebird::IConfigManager::DIR_INTL:
			s = "intl";
			break;

		case Firebird::IConfigManager::DIR_MISC:
			s = "misc";
			break;

		case Firebird::IConfigManager::DIR_MSG:
			gds__prefix_msg(tmp, name);
			return tmp;

		default:
			fb_assert(false);
			break;
	}

	if (s.hasData() && name[0])
	{
		s += '/';
	}
	s += name;
	gds__prefix(tmp, s.c_str());
	return tmp;
}
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;
}
Beispiel #15
0
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs, int nWndMode)
{
/**************************************
 *
 *      W i n M a i n
 *
 **************************************
 *
 * Functional description
 *      Run the server with NT named
 *      pipes and/or TCP/IP sockets.
 *
 **************************************/
	hInst = hThisInst;

	// We want server to crash without waiting for feedback from the user
	try
	{
		if (!Config::getBugcheckAbort())
			SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
	}
	catch (Firebird::fatal_exception& e)
	{
		MessageBox(NULL, e.what(), "Firebird server failure",
			MB_OK | MB_ICONHAND | MB_SYSTEMMODAL  | MB_DEFAULT_DESKTOP_ONLY);
		return STARTUP_ERROR; // see /jrd/common.h
	}
	catch (Firebird::status_exception& e)
	{
		TEXT buffer[BUFFER_LARGE];
		const ISC_STATUS* vector = e.value();
		if (! (vector && fb_interpret(buffer, sizeof(buffer), &vector)))
		{
			strcpy(buffer, "Unknown internal failure");
		}

		MessageBox(NULL, buffer, "Firebird server failure",
			MB_OK | MB_ICONHAND | MB_SYSTEMMODAL  | MB_DEFAULT_DESKTOP_ONLY);
		return STARTUP_ERROR; // see /jrd/common.h
	}

#ifdef SUPERSERVER
	server_flag = SRVR_multi_client;
#else
	server_flag = 0;
#endif

#ifdef SUPERSERVER
	SetProcessAffinityMask(GetCurrentProcess(), static_cast<DWORD>(Config::getCpuAffinityMask()));
#endif

	protocol_inet[0] = 0;
	protocol_wnet[0] = 0;

	strcpy(instance, FB_DEFAULT_INSTANCE);

	const HANDLE connection_handle = parse_args(lpszArgs, &server_flag);

#ifdef SUPERSERVER
	// get priority class from the config file
	int priority = Config::getProcessPriorityLevel();

	// override it, if necessary
	if (server_flag & SRVR_high_priority) {
		priority = 1;
	}

	// set priority class
	if (priority > 0) {
		SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
	}
	else if (priority < 0) {
		SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
	}
#endif

	TEXT mutex_name[MAXPATHLEN];
	fb_utils::snprintf(mutex_name, sizeof(mutex_name), SERVER_MUTEX, instance);
	fb_utils::prefix_kernel_object_name(mutex_name, sizeof(mutex_name));
	CreateMutex(ISC_get_security_desc(), FALSE, mutex_name);

	// Initialize the service

	ISC_signal_init();
	Firebird::FpeControl::maskAll();

	int nReturnValue = 0;
	ISC_STATUS_ARRAY status_vector;
	fb_utils::init_status(status_vector);

	fb_shutdown_callback(0, wait_threads, fb_shut_finish, NULL);

	if (connection_handle != INVALID_HANDLE_VALUE)
	{
		rem_port* port = 0;

		if (server_flag & SRVR_inet)
		{
			port = INET_reconnect((SOCKET) connection_handle, status_vector);

			if (port)
			{
				SRVR_multi_thread(port, server_flag);
				port = NULL;
			}
		}
		else if (server_flag & SRVR_wnet)
			port = WNET_reconnect(connection_handle, status_vector);
		else if (server_flag & SRVR_xnet)
			port = XNET_reconnect((ULONG) connection_handle, status_vector);

		if (port) {
			service_connection(port);
		}
		else if (status_vector[1])
			gds__log_status(0, status_vector);

		fb_shutdown(5 * 1000 /*5 seconds*/, fb_shutrsn_no_connection);
	}
	else if (!(server_flag & SRVR_non_service))
	{
		Firebird::string service_name;
		service_name.printf(REMOTE_SERVICE, instance);

		CNTL_init(start_connections_thread, 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");
			}
			server_flag |= SRVR_non_service;
		}
	}
	else
	{
		start_connections_thread(0);
		nReturnValue = WINDOW_main(hThisInst, nWndMode, server_flag);
	}

#ifdef DEBUG_GDS_ALLOC
	// In Debug mode - this will report all server-side memory leaks
	// due to remote access

	//gds_alloc_report(0, __FILE__, __LINE__);
	Firebird::PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_LOG, "memdebug.log");
	FILE* file = fopen(name.c_str(), "w+t");
	if (file)
	{
		fprintf(file, "Global memory pool allocated objects\n");
		getDefaultMemoryPool()->print_contents(file);
		fclose(file);
	}
#endif

	return nReturnValue;
}


THREAD_ENTRY_DECLARE process_connection_thread(THREAD_ENTRY_PARAM arg)
{
/**************************************
 *
 *      p r o c e s s _ c o n n e c t i o n _ t h r e a d
 *
 **************************************
 *
 * Functional description
 *
 **************************************/
	ThreadCounter counter;

	service_connection((rem_port*) arg);
	return 0;
}
Beispiel #16
0
int gsec(Firebird::UtilSvc* uSvc)
{
/**************************************
 *
 *	c o m m o n _ m a i n
 *
 **************************************
 *
 * Functional description
 *	If there is no command line, prompt for one, read it
 *	and make an artificial argv.   Otherwise, pass
 *	the specified argv to SECURITY_exec_line (see below).
 *
 **************************************/
	int exit_code = FINI_OK;
	Firebird::UtilSvc::ArgvType& argv = uSvc->argv;

	TEXT stuff[MAXSTUFF];		// a place to put stuff in interactive mode

	tsec tsecInstance(uSvc);
	tsec* tdsec = &tsecInstance;
	tsec::putSpecific(tdsec);

	StackUserData u;
	tdsec->tsec_user_data = &u;

	const unsigned char* block;
	unsigned int bs = uSvc->getAuthBlock(&block);
	if (bs)
	{
		u.authenticationBlock.add(block, bs);
	}

	try {
	// Perform some special handling when run as a Firebird service.

	tdsec->tsec_throw = true;
	tdsec->tsec_interactive = !uSvc->isService();
	UserData* user_data = tdsec->tsec_user_data;

	//if (!uSvc->isService() && argv.getCount() == 1)
	//	GSEC_error(GsecMsg101); // use gsec -? to get help

	int ret = parse_cmd_line(argv, tdsec);
	if (!uSvc->isService() && ret == -2) // user asked for help
		GSEC_exit();

	Firebird::PathName databaseName;
	const bool databaseNameEntered = user_data->database.entered();
	if (databaseNameEntered)
	{
		databaseName = user_data->database.get();
	}
	else
	{
		const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig());
		databaseName = defConf->getSecurityDatabase();
	}

	const Firebird::string sqlRoleName(user_data->role.entered() ? user_data->role.get() : "");

	Firebird::PathName serverName;
	const bool useServices = !uSvc->isService();

	switch (ISC_extract_host(databaseName, serverName, true))
	{
	case ISC_PROTOCOL_TCPIP:
		serverName += ":";
		break;
	case ISC_PROTOCOL_WLAN:
		serverName = "\\\\" + serverName + "\\";
		break;
	}

	if (!useServices)
	{
		serverName = "";
	}
	Firebird::LocalStatus s;
	user_data->database.set(&s, databaseName.c_str());
	check(&s);

	Firebird::RefPtr<IManagement> manager;
	ISC_STATUS_ARRAY status;

	if (!useServices)
	{
		// Get remote address info for management plugin
		Firebird::string network_protocol, remote_address;
		Firebird::ClumpletWriter tmp(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1);
		uSvc->fillDpb(tmp);

		if (tmp.find(isc_dpb_address_path))
		{
			Firebird::ClumpletReader address_stack(Firebird::ClumpletReader::UnTagged,
												   tmp.getBytes(), tmp.getClumpLength());

			while (!address_stack.isEof())
			{
				if (address_stack.getClumpTag() != isc_dpb_address)
				{
					address_stack.moveNext();
					continue;
				}

				Firebird::ClumpletReader address(Firebird::ClumpletReader::UnTagged,
												 address_stack.getBytes(), address_stack.getClumpLength());

				while (!address.isEof())
				{
					switch (address.getClumpTag())
					{
						case isc_dpb_addr_protocol:
							address.getString(network_protocol);
							break;
						case isc_dpb_addr_endpoint:
							address.getString(remote_address);
							break;
						default:
							break;
					}

					address.moveNext();
				}

				break;
			}
		}

		// Create config to pass -DATABASE parameter value to plugin
		Firebird::string databaseText;
		databaseText.printf("SecurityDatabase = %s\n", databaseName.c_str());
		ConfigFile gsecDatabase(ConfigFile::USE_TEXT, databaseText.c_str());
		Firebird::RefPtr<Config> defaultConfig(Config::getDefaultConfig());
		Firebird::RefPtr<Config> pseudoConfig(new Config(gsecDatabase, *defaultConfig));

		uSvc->checkService();

		fb_assert(user_data->dba.entered() || user_data->authenticationBlock.hasData());
		if (user_data->dba.entered() || user_data->authenticationBlock.hasData())
		{
			class GsecInfo : public Firebird::AutoIface<ILogonInfo, FB_AUTH_LOGON_INFO_VERSION>
			{
			public:
				GsecInfo(const char* pDba, const char* pRole,
						 const char* pProtocol, const char* pAddress,
						 const UserData::AuthenticationBlock* pAuthBlock)
					: dba(pDba), sqlRole(pRole),
					  protocol(pProtocol), address(pAddress),
					  authBytes(pAuthBlock->getCount() ? pAuthBlock->begin() : NULL),
					  authLength(pAuthBlock->getCount())
				{ }

				// ILogonInfo implementation
				const char* FB_CARG name()
				{
					return dba;
				}

				const char* FB_CARG role()
				{
					return sqlRole;
				}

				const char* FB_CARG networkProtocol()
				{
					return protocol;
				}

				const char* FB_CARG remoteAddress()
				{
					return address;
				}

				const unsigned char* FB_CARG authBlock(unsigned* length)
				{
					*length = authLength;
					return authBytes;
				}

			private:
				const char* dba;
				const char* sqlRole;
				const char* protocol;
				const char* address;
				const unsigned char* authBytes;
				unsigned int authLength;
			};
Beispiel #17
0
// Full processing of database name
// Returns true if alias was found in databases.conf
bool expandDatabaseName(Firebird::PathName alias,
						Firebird::PathName& file,
						Firebird::RefPtr<Config>* config)
{
	try
	{
		aliasesConf().checkLoadConfig();
	}
	catch (const fatal_exception& ex)
	{
		gds__log("File databases.conf contains bad data: %s", ex.what());
		Arg::Gds(isc_server_misconfigured).raise();
	}

	// remove whitespaces from database name
	alias.trim();

	ReadLockGuard guard(aliasesConf().rwLock, "expandDatabaseName");

	// First of all check in databases.conf
	if (resolveAlias(alias, file, config))
	{
		return true;
	}

	// Now try ISC_PATH environment variable
	if (!setPath(alias, file))
	{
		// At this step check DatabaseAccess paths in firebird.conf
		if (!resolveDatabaseAccess(alias, file))
		{
			// Last chance - regular filename expansion
			file = alias;

			ISC_systemToUtf8(file);
			ISC_unescape(file);
			ISC_utf8ToSystem(file);

			ISC_expand_filename(file, true);

			ISC_systemToUtf8(file);
			ISC_escape(file);
			ISC_utf8ToSystem(file);
		}
	}

	// Search for correct config in databases.conf
	if (config)
	{
		DbName* db = aliasesConf().dbHash.lookup(file);
#ifdef HAVE_ID_BY_NAME
		if (!db)
		{
			UCharBuffer id;
			os_utils::getUniqueFileId(file.c_str(), id);
			if (id.hasData())
			{
				Id* i = aliasesConf().idHash.lookup(id);
				if (i)
					db = i->db;
			}
		}
#endif
		*config = (db && db->config.hasData()) ? db->config : Config::getDefaultConfig();
	}

	return false;
}
int CLIB_ROUTINE main( int argc, char** argv)
{
/**************************************
 *
 *	m a i n
 *
 **************************************
 *
 * Functional description
 *	Run the server with apollo mailboxes.
 *
 **************************************/
	try
	{
		RemPortPtr port;

		// We should support 3 modes:
		// 1. Standalone single-process listener (like SS).
		// 2. Standalone listener, forking on each packet accepted (look -s switch in CS).
		// 3. Process spawned by (x)inetd (like CS).
		bool classic = false;
		bool standaloneClassic = false;
		bool super = false;

		// It's very easy to detect that we are spawned - just check fd 0 to be a socket.
		const int channel = 0;
		struct stat stat0;
		if (fstat(channel, &stat0) == 0 && S_ISSOCK(stat0.st_mode))
		{
			// classic server mode
			classic = true;
		}

		const TEXT* const* const end = argc + argv;
		argv++;
		bool debug = false;
		USHORT INET_SERVER_flag = 0;
		protocol[0] = 0;

		bool done = false;

		while (argv < end)
		{
			TEXT c;
			const TEXT* p = *argv++;

			if (*p++ == '-')
			{
				while (c = *p++)
				{
					switch (UPPER(c))
					{
					case 'D':
						debug = true;
						break;

					case 'E':
						if (argv < end)
						{
							if (ISC_set_prefix(p, *argv) == -1)
								printf("Invalid argument Ignored\n");
							else
								argv++;	// do not skip next argument if this one is invalid
						}
						else
						{
							printf("Missing argument, switch -E ignored\n");
						}
						done = true;
						break;

					case 'P':
						if (argv < end)
						{
							if (!classic)
							{
								fb_utils::snprintf(protocol, sizeof(protocol), "/%s", *argv++);
							}
							else
							{
								gds__log("Switch -P ignored in CS mode\n");
							}
						}
						else
						{
							printf("Missing argument, switch -P ignored\n");
						}
						break;

		            case 'H':
					case '?':
						printf("Firebird TCP/IP server options are:\n");
						printf("  -d        : debug on\n");
						printf("  -p <port> : specify port to listen on\n");
						printf("  -z        : print version and exit\n");
						printf("  -h|?      : print this help\n");
		                printf("\n");
		                printf("  (The following -e options used to be -h options)\n");
						printf("  -e <firebird_root_dir>   : set firebird_root path\n");
						printf("  -el <firebird_lock_dir>  : set runtime firebird_lock dir\n");
						printf("  -em <firebird_msg_dir>   : set firebird_msg dir path\n");

						exit(FINI_OK);

					case 'Z':
						printf("Firebird TCP/IP server version %s\n", FB_VERSION);
						exit(FINI_OK);

					default:
						printf("Unknown switch '%c', ignored\n", c);
						break;
					}
					if (done)
						break;
				}
			}
		}

		if (Config::getServerMode() == MODE_CLASSIC)
		{
			if (!classic)
				standaloneClassic = true;
		}
		else
		{
			if (classic)
			{
				gds__log("Server misconfigured - to start it from (x)inetd add ServerMode=Classic to firebird.conf");
				Firebird::Syslog::Record(Firebird::Syslog::Error, "Server misconfigured - add ServerMode=Classic to firebird.conf");
				exit(STARTUP_ERROR);
			}
			INET_SERVER_flag |= SRVR_multi_client;
			super = true;
		}
		{	// scope
			Firebird::MasterInterfacePtr master;
			master->serverMode(super ? 1 : 0);
		}

		if (debug)
		{
			INET_SERVER_flag |= SRVR_debug;
		}

		// activate paths set with -e family of switches
		ISC_set_prefix(0, 0);

		// ignore some signals
		set_signal(SIGPIPE, signal_handler);
		set_signal(SIGUSR1, signal_handler);
		set_signal(SIGUSR2, signal_handler);

		// First of all change directory to tmp
		if (chdir(TEMP_DIR))
		{
			// error on changing the directory
			gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno);
		}

#ifdef FB_RAISE_LIMITS

#ifdef RLIMIT_NPROC
		raiseLimit(RLIMIT_NPROC);
#endif

#if !(defined(DEV_BUILD))
		if (Config::getBugcheckAbort())
#endif
		{
			// try to force core files creation
			raiseLimit(RLIMIT_CORE);
		}

#if (defined SOLARIS || defined HPUX || defined LINUX)
		if (super)
		{
			// Increase max open files to hard limit for Unix
			// platforms which are known to have low soft limits.

			raiseLimit(RLIMIT_NOFILE);
		}
#endif // Unix platforms

#endif // FB_RAISE_LIMITS

#ifdef HAVE_LOCALE_H
		// Pick up the system locale to allow SYSTEM<->UTF8 conversions inside the engine
		setlocale(LC_CTYPE, "");
#endif

		if (!(debug || classic))
		{
			int mask = 0; // FD_ZERO(&mask);
			mask |= 1 << 2; // FD_SET(2, &mask);
			divorce_terminal(mask);
		}

		// check firebird.conf presence - must be for server
		if (Config::missFirebirdConf())
		{
			Firebird::Syslog::Record(Firebird::Syslog::Error, "Missing master config file firebird.conf");
			exit(STARTUP_ERROR);
		}

		if (super || standaloneClassic)
		{
			try
			{
				port = INET_connect(protocol, 0, INET_SERVER_flag, 0, NULL);
			}
			catch (const Firebird::Exception& ex)
			{
				iscLogException("startup:INET_connect:", ex);
		 		Firebird::StaticStatusVector st;
				ex.stuffException(st);
				gds__print_status(st.begin());
				exit(STARTUP_ERROR);
			}
		}

		if (classic)
		{
			port = INET_server(channel);
			if (!port)
			{
				gds__log("Unable to start INET_server");
				Firebird::Syslog::Record(Firebird::Syslog::Error, "Unable to start INET_server");
				exit(STARTUP_ERROR);
			}
		}

		{ // scope for interface ptr
			Firebird::PluginManagerInterfacePtr pi;
			Auth::registerSrpServer(pi);
		}

		if (super)
		{
			// Server tries to attach to security2.fdb to make sure everything is OK
			// This code fixes bug# 8429 + all other bug of that kind - from
			// now on the server exits if it cannot attach to the database
			// (wrong or no license, not enough memory, etc.

			ISC_STATUS_ARRAY status;
			isc_db_handle db_handle = 0L;

			const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig());
			const char* path = defConf->getSecurityDatabase();
			const char dpb[] = {isc_dpb_version1, isc_dpb_sec_attach, 1, 1, isc_dpb_address_path, 0};

			isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb);
			if (status[0] == 1 && status[1] > 0)
			{
				logSecurityDatabaseError(path, status);
			}

			isc_detach_database(status, &db_handle);
			if (status[0] == 1 && status[1] > 0)
			{
				logSecurityDatabaseError(path, status);
			}
		} // end scope

		fb_shutdown_callback(NULL, closePort, fb_shut_exit, port);

		SRVR_multi_thread(port, INET_SERVER_flag);

#ifdef DEBUG_GDS_ALLOC
		// In Debug mode - this will report all server-side memory leaks due to remote access

		Firebird::PathName name = fb_utils::getPrefix(
			Firebird::IConfigManager::DIR_LOG, "memdebug.log");
		FILE* file = os_utils::fopen(name.c_str(), "w+t");
		if (file)
		{
			fprintf(file, "Global memory pool allocated objects\n");
			getDefaultMemoryPool()->print_contents(file);
			fclose(file);
		}
#endif

		// perform atexit shutdown here when all globals in embedded library are active
		// also sync with possibly already running shutdown in dedicated thread
		fb_shutdown(10000, fb_shutrsn_exit_called);

		return FINI_OK;
	}
	catch (const Firebird::Exception& ex)
	{
 		Firebird::StaticStatusVector st;
		ex.stuffException(st);

		char s[100];
		const ISC_STATUS* status = st.begin();
		fb_interpret(s, sizeof(s), &status);

		iscLogException("Firebird startup error:", ex);
		Firebird::Syslog::Record(Firebird::Syslog::Error, "Firebird startup error");
		Firebird::Syslog::Record(Firebird::Syslog::Error, s);

		exit(STARTUP_ERROR);
	}
}
Beispiel #19
0
bool PathUtils::canAccess(const Firebird::PathName& path, int mode)
{
	return access(path.c_str(), mode) == 0;
}
Beispiel #20
0
    int FB_EXPORTED server_main( int argc, char** argv)
    {
        /**************************************
         *
         *	m a i n
         *
         **************************************
         *
         * Functional description
         *	Run the server with apollo mailboxes.
         *
         **************************************/
        RemPortPtr port;

// 01 Sept 2003, Nickolay Samofatov
// In GCC version 3.1-3.3 we need to install special error handler
// in order to get meaningful terminate() error message on stderr.
// In GCC 3.4 or later this is the default.
//#if __GNUC__ == 3 && __GNUC_MINOR__ >= 1 && __GNUC_MINOR__ < 4
//    std::set_terminate (__gnu_cxx::__verbose_terminate_handler);
//#endif

        const TEXT* const* const end = argc + argv;
        argv++;
        bool debug = false, standalone = false;
        INET_SERVER_flag = 0;
        int channel = 0;
        protocol[0] = 0;
        bool multi_client = false, multi_threaded = false;

#ifdef SUPERSERVER
        INET_SERVER_flag |= SRVR_multi_client;
        multi_client = multi_threaded = standalone = true;
#endif

        int clients = 0;
        bool done = false;

        while (argv < end)
        {
            TEXT c;
            const TEXT* p = *argv++;
            if (*p++ == '-')
                while (c = *p++)
                {
                    switch (UPPER(c))
                    {
                    case 'D':
                        INET_SERVER_flag |= SRVR_debug;
                        debug = true;
                        break;
#ifndef SUPERSERVER

                    case 'M':
                        INET_SERVER_flag |= SRVR_multi_client;
                        if (argv < end)
                        {
                            if (clients = atoi(*argv))
                                argv++;
                        }
                        multi_client = standalone = true;
                        break;

                    case 'S':
                        standalone = true;
                        break;


                    case 'I':
                        standalone = false;
                        break;

                    case 'T':
                        multi_threaded = true;
                        break;

                    case 'U':
                        multi_threaded = false;
                        break;
#endif // SUPERSERVER

                    case 'E':
                        if (ISC_set_prefix(p, *argv) == -1)
                            printf("Invalid argument Ignored\n");
                        else
                            argv++;	// do not skip next argument if this one is invalid
                        done = true;
                        break;

                    case 'P':
                        fb_utils::snprintf(protocol, sizeof(protocol), "/%s", *argv++);
                        break;

                    case 'H':
                    case '?':
                        printf("Firebird TCP/IP server options are:\n");
                        printf("  -d           : debug on\n");

#ifndef SUPERSERVER
                        // These options are not applicable to super server
                        printf("  -m           : multiclient - on\n");
                        printf("  -s           : standalone - true\n");
                        printf("  -i           : standalone - false\n");

                        printf("  -t           : multithread - true  (non pc only)\n");
                        printf("  -u           : multithread - false (pc only)\n");
#endif

                        printf("  -p<protocol> : specify protocol\n");
                        printf("  -h|? : print this help\n");
                        printf("\n");
                        printf("  (The following -e options used to be -h options)\n");
                        printf("  -e <firebird_root_dir>   : set firebird_root path\n");
                        printf("  -el <firebird_lock_dir>  : set runtime firebird_lock dir\n");
                        printf("  -em <firebird_msg_dir>   : set firebird_msg dir path\n");
                        printf("  -z   : print version\n");

                        exit(FINI_OK);
                    case 'Z':
                        printf("Firebird TCP/IP server version %s\n", GDS_VERSION);
                        exit(FINI_OK);
                    }
                    if (done)
                        break;
                }
        }

        // activate paths set with -e family of switches
        ISC_set_prefix(0, 0);

#ifdef UNIX
        set_signal(SIGPIPE, signal_handler);
        set_signal(SIGUSR1, signal_handler);
        set_signal(SIGUSR2, signal_handler);
#endif

#if defined(UNIX) && defined(HAVE_SETRLIMIT) && defined(HAVE_GETRLIMIT)

#ifdef RLIMIT_NPROC
        raiseLimit(RLIMIT_NPROC);
#endif

#if !(defined(DEV_BUILD))
        if (Config::getBugcheckAbort())
#endif
        {
            // try to force core files creation
            raiseLimit(RLIMIT_CORE);

            // we need some writable directory for core file
            // on any unix /tmp seems to be the best place
            if (CHANGE_DIR(TEMP_DIR))
            {
                // error on changing the directory
                gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno);
            }
        }

#if defined(SUPERSERVER) && (defined SOLARIS || defined HPUX || defined LINUX)
        // Increase max open files to hard limit for Unix
        // platforms which are known to have low soft limits.

        raiseLimit(RLIMIT_NOFILE);
#endif

#endif

        // Fork off a server, wait for it to die, then fork off another,
        // but give up after 100 tries

#ifndef SUPERSERVER
        if (multi_client && !debug)
        {
#ifdef UNIX
            set_signal(SIGUSR1, signal_handler);
#endif
            int child;
            for (int n = 0; n < 100; n++)
            {
                INET_SERVER_start = 0;
                if (!(child = fork()))
                    break;
                while (wait(0) != child)
                    if (INET_SERVER_start)
                    {
                        n = 0;		// reset error counter on "real" signal
                        break;
                    }
                gds__log("INET_SERVER/main: gds_inet_server restarted");
            }
#ifdef UNIX
            set_signal(SIGUSR1, SIG_DFL);
#endif
        }
#endif

        if (standalone)
        {
            if (multi_client)
            {
#ifdef SUPERSERVER

                // Remove restriction on username, for DEV builds
                // restrict only for production builds.  MOD 21-July-2002
#ifndef DEV_BUILD
                Firebird::string user_name;	// holds the user name
                // check user id
                ISC_get_user(&user_name, NULL, NULL, NULL);

                if (user_name != "root" &&
                        user_name != FIREBIRD_USER_NAME &&
                        user_name != INTERBASE_USER_NAME &&
                        user_name != INTERBASE_USER_SHORT)
                {
                    // invalid user -- bail out
                    fprintf(stderr, "%s: Invalid user (must be %s, %s, %s or root).\n",
                            "fbserver", FIREBIRD_USER_NAME,
                            INTERBASE_USER_NAME, INTERBASE_USER_SHORT);
                    exit(STARTUP_ERROR);
                }
#endif
#else
                if (setreuid(0, 0) < 0)
                    printf("Inet_server: couldn't set uid to superuser.\n");
#endif
                INET_set_clients(clients);
            }

            if (!debug)
            {
                int mask = 0; // FD_ZERO(&mask);
                mask |= 1 << 2; // FD_SET(2, &mask);
                divorce_terminal(mask);
            }
            {   // scope block
                ISC_STATUS_ARRAY status_vector;
                port = INET_connect(protocol, 0, status_vector, INET_SERVER_flag, 0);
                if (!port)
                {
                    gds__print_status(status_vector);
                    exit(STARTUP_ERROR);
                }
            } // end scope block
        }
        else
        {
            port = INET_server(channel);
            if (!port)
            {
                fprintf(stderr, "fbserver: Unable to start INET_server\n");
                exit(STARTUP_ERROR);
            }
        }

#ifdef SUPERSERVER
        // before starting the superserver stuff change directory to tmp
        if (CHANGE_DIR(TEMP_DIR))
        {
            // error on changing the directory
            gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno);
        }

        // Server tries to attach to security2.fdb to make sure everything is OK
        // This code fixes bug# 8429 + all other bug of that kind - from
        // now on the server exits if it cannot attach to the database
        // (wrong or no license, not enough memory, etc.

        {   // scope
            TEXT path[MAXPATHLEN];
            ISC_STATUS_ARRAY status;
            isc_db_handle db_handle = 0L;

            Jrd::SecurityDatabase::getPath(path);
            const char dpb[] = {isc_dpb_version1, isc_dpb_gsec_attach, 1, 1};
            isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb);
            if (status[0] == 1 && status[1] > 0)
            {
                gds__log_status(path, status);
                isc_print_status(status);
                exit(STARTUP_ERROR);
            }
            isc_detach_database(status, &db_handle);
            if (status[0] == 1 && status[1] > 0)
            {
                gds__log_status(path, status);
                isc_print_status(status);
                exit(STARTUP_ERROR);
            }
        } // end scope

        shutdownInit();
#endif

        SRVR_multi_thread(port, INET_SERVER_flag);

#ifdef DEBUG_GDS_ALLOC
        // In Debug mode - this will report all server-side memory leaks due to remote access

        //gds_alloc_report(0, __FILE__, __LINE__);
        Firebird::PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_LOG, "memdebug.log");
        FILE* file = fopen(name.c_str(), "w+t");
        if (file)
        {
            fprintf(file, "Global memory pool allocated objects\n");
            getDefaultMemoryPool()->print_contents(file);
            fclose(file);
        }
#endif

        // perform atexit shutdown here when all globals in embedded library are active
        // also sync with possibly already running shutdown in dedicated thread
        fb_shutdown(10000, fb_shutrsn_exit_called);

        return FINI_OK;
    }