| /* |
| Copyright (C) 2012 Samsung Electronics |
| Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public License |
| along with this library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "config.h" |
| #include "ProcessLauncher.h" |
| |
| #include "Connection.h" |
| #include "ProcessExecutablePath.h" |
| #include <WebCore/AuthenticationChallenge.h> |
| #include <WebCore/FileSystem.h> |
| #include <WebCore/NetworkingContext.h> |
| #include <WebCore/ResourceHandle.h> |
| #include <sys/socket.h> |
| #include <wtf/RunLoop.h> |
| #include <wtf/StdLibExtras.h> |
| #include <wtf/text/CString.h> |
| #include <wtf/text/WTFString.h> |
| |
| using namespace WebCore; |
| |
| namespace WebKit { |
| |
| static Vector<std::unique_ptr<char[]>> createArgsArray(const String& prefix, const String& executablePath, const String& socket, const String& pluginPath) |
| { |
| ASSERT(!executablePath.isEmpty()); |
| ASSERT(!socket.isEmpty()); |
| |
| Vector<String> splitArgs; |
| prefix.split(' ', splitArgs); |
| |
| splitArgs.append(executablePath); |
| splitArgs.append(socket); |
| if (!pluginPath.isEmpty()) |
| splitArgs.append(pluginPath); |
| |
| Vector<std::unique_ptr<char[]>> args; |
| args.resize(splitArgs.size() + 1); // Extra room for null. |
| |
| size_t numArgs = splitArgs.size(); |
| for (size_t i = 0; i < numArgs; ++i) { |
| CString param = splitArgs[i].utf8(); |
| args[i] = std::make_unique<char[]>(param.length() + 1); // Room for the terminating null coming from the CString. |
| strncpy(args[i].get(), param.data(), param.length() + 1); // +1 here so that strncpy copies the ending null. |
| } |
| // execvp() needs the pointers' array to be null-terminated. |
| args[numArgs] = nullptr; |
| |
| return args; |
| } |
| |
| static void parseAndRemoveEnvironments(Vector<std::unique_ptr<char[]>>& args) |
| { |
| // Handle environment variable specified before executable file name only for this process use. |
| auto end = args.end(); |
| auto it = args.begin(); |
| int argsLength = 0; |
| |
| for (; it != end; ++it) { |
| const char* key; |
| const char* value; |
| auto arg = (*it).get(); |
| |
| if (strchr(arg, '=') == nullptr) |
| break; |
| |
| key = strtok(arg, "="); |
| value = strtok(nullptr, "="); |
| |
| if (key == nullptr) { |
| argsLength++; |
| continue; |
| } |
| |
| setenv(key, value, 1); |
| argsLength++; |
| } |
| |
| args.remove(0, argsLength); |
| } |
| |
| void ProcessLauncher::launchProcess() |
| { |
| int sockets[2]; |
| if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) { |
| ASSERT_NOT_REACHED(); |
| return; |
| } |
| |
| String processCmdPrefix, executablePath, pluginPath; |
| switch (m_launchOptions.processType) { |
| case ProcessLauncher::ProcessType::Web: |
| executablePath = executablePathOfWebProcess(); |
| break; |
| #if ENABLE(PLUGIN_PROCESS) |
| case ProcessLauncher::ProcessType::Plugin64: |
| case ProcessLauncher::ProcessType::Plugin32: |
| executablePath = executablePathOfPluginProcess(); |
| pluginPath = m_launchOptions.extraInitializationData.get("plugin-path"); |
| break; |
| #endif |
| case ProcessLauncher::ProcessType::Network: |
| executablePath = executablePathOfNetworkProcess(); |
| break; |
| #if ENABLE(DATABASE_PROCESS) |
| case ProcessLauncher::ProcessType::Database: |
| executablePath = executablePathOfDatabaseProcess(); |
| break; |
| #endif |
| default: |
| ASSERT_NOT_REACHED(); |
| return; |
| } |
| |
| #if ENABLE(DEVELOPER_MODE) |
| if (!m_launchOptions.processCmdPrefix.isEmpty()) |
| processCmdPrefix = m_launchOptions.processCmdPrefix; |
| #endif |
| auto args = createArgsArray(processCmdPrefix, executablePath, String::number(sockets[0]), pluginPath); |
| |
| parseAndRemoveEnvironments(args); |
| |
| // Do not perform memory allocation in the middle of the fork() |
| // exec() below. FastMalloc can potentially deadlock because |
| // the fork() doesn't inherit the running threads. |
| pid_t pid = fork(); |
| if (!pid) { // Child process. |
| close(sockets[1]); |
| execvp(args.data()[0].get(), reinterpret_cast<char* const*>(args.data())); |
| } else if (pid > 0) { // parent process; |
| close(sockets[0]); |
| m_processIdentifier = pid; |
| // We've finished launching the process, message back to the main run loop. |
| RefPtr<ProcessLauncher> protector(this); |
| IPC::Connection::Identifier serverSocket = sockets[1]; |
| RunLoop::main().dispatch([protector, pid, serverSocket] { |
| protector->didFinishLaunchingProcess(pid, serverSocket); |
| }); |
| } else { |
| ASSERT_NOT_REACHED(); |
| return; |
| } |
| } |
| |
| void ProcessLauncher::terminateProcess() |
| { |
| if (m_isLaunching) { |
| invalidate(); |
| return; |
| } |
| |
| if (!m_processIdentifier) |
| return; |
| kill(m_processIdentifier, SIGKILL); |
| m_processIdentifier = 0; |
| } |
| |
| void ProcessLauncher::platformInvalidate() |
| { |
| } |
| |
| } // namespace WebKit |