Example #1
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;
}
Example #2
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));
}
Example #3
0
void ModuleLoader::doctorModuleExtention(Firebird::PathName& name)
{
    Firebird::PathName::size_type pos = name.rfind(".dylib");
    if (pos != Firebird::PathName::npos && pos == name.length() - 6)
        return;		// No doctoring necessary
    name += ".dylib";
}
Example #4
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();
}
Example #5
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;
		}
	}
}
Example #6
0
// We don't work correctly with MBCS.
void PathUtils::ensureSeparator(Firebird::PathName& in_out)
{
	if (in_out.length() == 0)
		in_out = PathUtils::dir_sep;

	if (in_out[in_out.length() - 1] != PathUtils::dir_sep)
		in_out += PathUtils::dir_sep;
}
Example #7
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;
}
Example #8
0
void PathUtils::splitPrefix(Firebird::PathName& path, Firebird::PathName& prefix)
{
	prefix.erase();
	while (path.hasData() && path[0] == dir_sep)
	{
		prefix = dir_sep;
		path.erase(0, 1);
	}
}
Example #9
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;
}
Example #10
0
void getCwd(Firebird::PathName& pn)
{
	char* buffer = pn.getBuffer(MAXPATHLEN);
#if defined(WIN_NT)
	_getcwd(buffer, MAXPATHLEN);
#elif defined(HAVE_GETCWD)
	FB_UNUSED(getcwd(buffer, MAXPATHLEN));
#else
	FB_UNUSED(getwd(buffer));
#endif
	pn.recalculate_length();
}
Example #11
0
TempFile* TempSpace::setupFile(size_t size)
{
	ISC_STATUS_ARRAY status_vector = {0};

	for (size_t i = 0; i < tempDirs->getCount(); i++)
	{
		TempFile* file = NULL;

		Firebird::PathName directory = (*tempDirs)[i];
		PathUtils::ensureSeparator(directory);

		for (size_t j = 0; j < tempFiles.getCount(); j++)
		{
			Firebird::PathName dirname, filename;
			PathUtils::splitLastComponent(dirname, filename, tempFiles[j]->getName());
			PathUtils::ensureSeparator(dirname);
			if (!directory.compare(dirname))
			{
				file = tempFiles[j];
				break;
			}
		}

		try
		{
			if (!file)
			{
				file = FB_NEW(pool) TempFile(pool, filePrefix, directory);
				tempFiles.add(file);
			}

			file->extend(size);
		}
		catch (const Firebird::system_error& ex)
		{
			ex.stuff_exception(status_vector);
			continue;
		}

		return file;
	}

	// no room in all directories
	Firebird::Arg::Gds status(isc_out_of_temp_space);
	status.append(Firebird::Arg::StatusVector(status_vector));
	iscLogStatus(NULL, status.value());
	status.raise();

	return NULL; // compiler silencer
}
Example #12
0
void PathUtils::splitPrefix(Firebird::PathName& path, Firebird::PathName& prefix)
{
	prefix.erase();
	if (hasDriveLetter(path))
	{
		prefix = path.substr(0, 2);
		path.erase(0, 2);
	}
	if (path.hasData() && (path[0] == PathUtils::dir_sep || path[0] == '/'))
	{
		prefix += path[0];
		path.erase(0, 1);
	}
}
Example #13
0
void ModuleLoader::doctorModuleExtension(Firebird::PathName& name)
{
	Firebird::PathName::size_type pos = name.rfind('/');
	pos = (pos == Firebird::PathName::npos) ? 0 : pos + 1;
	if (name.find("lib", pos) != pos)
	{
		name.insert(pos, "lib");
	}

	pos = name.rfind(".dylib");
	if (pos == name.length() - 6)
		return;
	name += ".dylib";
}
Example #14
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;
}
Example #15
0
bool readenv(const char* env_name, Firebird::PathName& env_value)
{
	Firebird::string result;
	bool rc = readenv(env_name, result);
	env_value.assign(result.c_str(), result.length());
	return rc;
}
Example #16
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;
}
Example #17
0
bool PathUtils::isRelative(const Firebird::PathName& path)
{
	if (path.length() > 0)
	{
		char ds = path[0];
		if (path.length() > 2) {
			if (path[1] == ':' &&
				(('A' <= path[0] && path[0] <= 'Z') ||
				 ('a' <= path[0] && path[0] <= 'z')))
			{
				ds = path[2];
			}
		}
		return ds != PathUtils::dir_sep && ds != '/';
	}
	return true;
}
Example #18
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);
}
Example #19
0
bool ModuleLoader::doctorModuleExtension(Firebird::PathName& name, int& step)
{
	if (name.isEmpty())
		return false;

	switch (step++)
	{
	case 0: // Step 0: append missing extension
		{
			Firebird::PathName::size_type pos = name.rfind("." SHRLIB_EXT);
			if (pos != name.length() - 3)
			{
				pos = name.rfind("." SHRLIB_EXT ".");
				if (pos == Firebird::PathName::npos)
				{
					name += "." SHRLIB_EXT;
					return true;
				}
			}
			step++; // instead of break
		}
	case 1: // Step 1: insert missing prefix
		{
			Firebird::PathName::size_type pos = name.rfind('/');
			pos = (pos == Firebird::PathName::npos) ? 0 : pos + 1;
			if (name.find("lib", pos) != pos)
			{
				name.insert(pos, "lib");
				return true;
			}
		}
	}
	return false;
}
Example #20
0
bool PathUtils::isRelative(const Firebird::PathName& path)
{
	if (path.length() > 0)
	{
		const char ds = hasDriveLetter(path) ? path[2] : path[0];
		return ds != PathUtils::dir_sep && ds != '/';
	}
	return true;
}
Example #21
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());
	}
}
Example #22
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);
}
Example #23
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);
		*config = (db && db->config.hasData()) ? db->config : Config::getDefaultConfig();
	}

	return false;
}
Example #24
0
void PathUtils::concatPath(Firebird::PathName& result,
		const Firebird::PathName& first,
		const Firebird::PathName& second)
{
	if (second.length() == 0)
	{
		result = first;
		return;
	}
	if (first.length() == 0)
	{
		result = second;
		return;
	}

	if (first[first.length() - 1] != dir_sep &&
		second[0] != dir_sep)
	{
		result = first + dir_sep + second;
		return;
	}
	if (first[first.length() - 1] == dir_sep &&
		second[0] == dir_sep)
	{
		result = first;
		result.append(second, 1, second.length() - 1);
		return;
	}

	result = first + second;
}
Example #25
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);
}
Example #26
0
void PathUtils::splitLastComponent(Firebird::PathName& path, Firebird::PathName& file,
		const Firebird::PathName& orgPath)
{
	Firebird::PathName::size_type pos = orgPath.rfind(dir_sep);
	if (pos == Firebird::PathName::npos)
	{
		path = "";
		file = orgPath;
		return;
	}

	path.erase();
	path.append(orgPath, 0, pos);	// skip the directory separator
	file.erase();
	file.append(orgPath, pos + 1, orgPath.length() - pos - 1);
}
Example #27
0
void ModuleLoader::doctorModuleExtension(Firebird::PathName& name)
{
	if (name.isEmpty())
		return;

	Firebird::PathName::size_type pos = name.rfind("." SHRLIB_EXT);
	if (pos != name.length() - 3)
	{
		name += "." SHRLIB_EXT;
	}
	pos = name.rfind('/');
	pos = (pos == Firebird::PathName::npos) ? 0 : pos + 1;
	if (name.find("lib", pos) != pos)
	{
		name.insert(pos, "lib");
	}
}
Example #28
0
void PathUtils::splitLastComponent(Firebird::PathName& path, Firebird::PathName& file,
		const Firebird::PathName& orgPath)
{
	Firebird::PathName::size_type pos = orgPath.rfind(PathUtils::dir_sep);
	if (pos == Firebird::PathName::npos)
	{
		pos = orgPath.rfind('/');	// temp hack to make it work with paths,
									// not expanded by ISC_expand_filename
		if (pos == Firebird::PathName::npos)
		{
			path = "";
			file = orgPath;
			return;
		}
	}

	path.erase();
	path.append(orgPath, 0, pos);	// skip the directory separator
	file.erase();
	file.append(orgPath, pos + 1, orgPath.length() - pos - 1);
}
Example #29
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;
}