// ------------------------------------------------------------------------------------------------ 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; }
/* * 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 }