Example #1
0
// ------------------------------------------------------------------------------------------------
SQInteger LookupResult::GetValue(HSQUIRRELVM vm)
{
    const Int32 top = sq_gettop(vm);
    // The lookup result instance
    LookupResult * lookup = nullptr;
    // Attempt to extract the lookup result instance
    try
    {
        lookup = Var< LookupResult * >(vm, 1).value;
    }
    catch (const Sqrat::Exception & e)
    {
        return sq_throwerror(vm, e.what());
    }
    // Do we have a valid lookup result instance?
    if (!lookup)
    {
        return sq_throwerror(vm, "Invalid lookup result instance");
    }
    // See if there's a handle
    else if (!lookup->m_Handle)
    {
        return sq_throwerror(vm, "Invalid Maxmind database reference");
    }
    // See if there's an entry
    else if (!(lookup->m_Result.found_entry))
    {
        return sq_throwerror(vm, "Result does not have an entry");
    }

    typedef std::vector< StackStrF > ArgList;
    // The list of extracted arguments
    ArgList arglist;
    // Extract each argument as a string
    for (SQInteger i = 2; i <= top; ++i)
    {
        arglist.emplace_back(vm, i, false);
        // Did we fail to extract the argument value?
        if (SQ_FAILED(arglist.back().mRes))
        {
            return arglist.back().mRes; // Propagate the error
        }
    }

    typedef std::vector< CSStr > PtrList;
    // The list of pointers to path segments
    PtrList ptrlist;
    // Grab the pointers to argument values
    for (const auto & a : arglist)
    {
        ptrlist.push_back(a.mPtr);
    }
    // Push null to specify the end of the list
    ptrlist.push_back(nullptr);

    MMDB_entry_data_s entry_data;
    // Attempt to retrieve the specified entry data
    const int status = MMDB_aget_value(&(lookup->m_Result.entry), &entry_data, ptrlist.data());
    // Validate the status code
    if (status != MMDB_SUCCESS)
    {
        return sq_throwerror(vm, ToStrF("Unable to get entry data [%s]", MMDB_strerror(status)));
    }
    // Push the resulted list object onto the stack
    try
    {
        ClassType< EntryData >::PushInstance(vm, new EntryData(lookup->m_Handle, entry_data));
    }
    catch (const Sqrat::Exception & e)
    {
        return sq_throwerror(vm, e.what());
    }
    // Specify that we returned a value
    return 1;
}
Example #2
0
/*
* Returns file descriptor of the read-pipe or -1 on error.
*/
void ScriptController::StartProcess(int* pipein, int* pipeout)
{
	CString workingDir = m_workingDir;
	if (workingDir.Empty())
	{
		workingDir = FileSystem::GetCurrentDirectory();
	}

	const char* script = m_args[0];

#ifdef WIN32
	char* cmdLine = m_cmdLine;
	char cmdLineBuf[2048];
	if (!*m_cmdLine)
	{
		BuildCommandLine(cmdLineBuf, sizeof(cmdLineBuf));
		cmdLine = cmdLineBuf;
	}

	debug("Starting process: %s", cmdLine);

	WString wideWorkingDir = FileSystem::UtfPathToWidePath(workingDir);
	if (strlen(workingDir) > 260 - 14)
	{
		GetShortPathNameW(wideWorkingDir, wideWorkingDir, wideWorkingDir.Length() + 1);
	}

	// create pipes to write and read data
	HANDLE readPipe, readProcPipe;
	HANDLE writePipe = 0, writeProcPipe = 0;
	SECURITY_ATTRIBUTES securityAttributes = { 0 };
	securityAttributes.nLength = sizeof(securityAttributes);
	securityAttributes.bInheritHandle = TRUE;

	CreatePipe(&readPipe, &readProcPipe, &securityAttributes, 0);
	SetHandleInformation(readPipe, HANDLE_FLAG_INHERIT, 0);

	if (m_needWrite)
	{
		CreatePipe(&writeProcPipe, &writePipe, &securityAttributes, 0);
		SetHandleInformation(writePipe, HANDLE_FLAG_INHERIT, 0);
	}

	STARTUPINFOW startupInfo = { 0 };
	startupInfo.cb = sizeof(startupInfo);
	startupInfo.dwFlags = STARTF_USESTDHANDLES;
	startupInfo.hStdInput = writeProcPipe;
	startupInfo.hStdOutput = readProcPipe;
	startupInfo.hStdError = readProcPipe;

	PROCESS_INFORMATION processInfo = { 0 };

	std::unique_ptr<wchar_t[]> environmentStrings = m_environmentStrings.GetStrings();

	BOOL ok = CreateProcessW(nullptr, WString(cmdLine), nullptr, nullptr, TRUE,
		NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP | CREATE_UNICODE_ENVIRONMENT,
		environmentStrings.get(), wideWorkingDir, &startupInfo, &processInfo);
	if (!ok)
	{
		DWORD errCode = GetLastError();
		char errMsg[255];
		errMsg[255 - 1] = '\0';
		if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, errCode, 0, errMsg, 255, nullptr))
		{
			PrintMessage(Message::mkError, "Could not start %s: %s", *m_infoName, errMsg);
		}
		else
		{
			PrintMessage(Message::mkError, "Could not start %s: error %i", *m_infoName, errCode);
		}
		if (!FileSystem::FileExists(script))
		{
			PrintMessage(Message::mkError, "Could not find file %s", script);
		}
		if (wcslen(wideWorkingDir) > 260)
		{
			PrintMessage(Message::mkError, "Could not build short path for %s", workingDir);
		}
		CloseHandle(readPipe);
		CloseHandle(readProcPipe);
		CloseHandle(writePipe);
		CloseHandle(writeProcPipe);
		return;
	}

	debug("Child Process-ID: %i", (int)processInfo.dwProcessId);

	m_processId = processInfo.hProcess;
	m_dwProcessId = processInfo.dwProcessId;

	// close unused pipe ends
	CloseHandle(readProcPipe);
	CloseHandle(writeProcPipe);

	*pipein = _open_osfhandle((intptr_t)readPipe, _O_RDONLY);
	if (m_needWrite)
	{
		*pipeout = _open_osfhandle((intptr_t)writePipe, _O_WRONLY);
	}

#else

	int pin[] = {0, 0};
	int pout[] = {0, 0};

	// create the pipes
	if (pipe(pin))
	{
		PrintMessage(Message::mkError, "Could not open read pipe: errno %i", errno);
		return;
	}
	if (m_needWrite && pipe(pout))
	{
		PrintMessage(Message::mkError, "Could not open write pipe: errno %i", errno);
		close(pin[0]);
		close(pin[1]);
		return;
	}

	*pipein = pin[0];
	*pipeout = pout[1];

	std::vector<char*> environmentStrings = m_environmentStrings.GetStrings();
	char** envdata = environmentStrings.data();

	ArgList args;
	std::copy(m_args.begin(), m_args.end(), std::back_inserter(args));
	args.emplace_back(nullptr);
	char* const* argdata = (char* const*)args.data();

#ifdef DEBUG
	debug("Starting  process: %s", script);
	for (const char* arg : m_args)
	{
		debug("arg: %s", arg);
	}
#endif

	debug("forking");
	pid_t pid = fork();

	if (pid == -1)
	{
		PrintMessage(Message::mkError, "Could not start %s: errno %i", *m_infoName, errno);
		close(pin[0]);
		close(pin[1]);
		if (m_needWrite)
		{
			close(pout[0]);
			close(pout[1]);
		}
		return;
	}
	else if (pid == 0)
	{
		// here goes the second instance

		// only certain functions may be used here or the program may hang.
		// for a list of functions see chapter "async-signal-safe functions" in
		// http://man7.org/linux/man-pages/man7/signal.7.html

		// create new process group (see Terminate() where it is used)
		setsid();

		// make the pipeout to be the same as stdout and stderr
		dup2(pin[1], 1);
		dup2(pin[1], 2);
		close(pin[0]);
		close(pin[1]);

		if (m_needWrite)
		{
			// make the pipein to be the same as stdin
			dup2(pout[0], 0);
			close(pout[0]);
			close(pout[1]);
		}

#ifdef CHILD_WATCHDOG
		write(1, "\n", 1);
		fsync(1);
#endif

		chdir(workingDir);
		environ = envdata;

		execvp(script, argdata);

		if (errno == EACCES)
		{
			write(1, "[WARNING] Fixing permissions for", 32);
			write(1, script, strlen(script));
			write(1, "\n", 1);
			fsync(1);
			FileSystem::FixExecPermission(script);
			execvp(script, argdata);
		}

		// NOTE: the text "[ERROR] Could not start " is checked later,
		// by changing adjust the dependent code below.
		write(1, "[ERROR] Could not start ", 24);
		write(1, script, strlen(script));
		write(1, ": ", 2);
		char* errtext = strerror(errno);
		write(1, errtext, strlen(errtext));
		write(1, "\n", 1);
		fsync(1);
		_exit(FORK_ERROR_EXIT_CODE);
	}

	// continue the first instance
	debug("forked");
	debug("Child Process-ID: %i", (int)pid);

	m_processId = pid;

	// close unused pipe ends
	close(pin[1]);
	if (m_needWrite)
	{
		close(pout[0]);
	}
#endif
}