1/*
2    Copyright (C) 2012 Samsung Electronics
3    Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "ProcessLauncher.h"
23
24#include "Connection.h"
25#include "ProcessExecutablePath.h"
26#include <WebCore/AuthenticationChallenge.h>
27#include <WebCore/FileSystem.h>
28#include <WebCore/NetworkingContext.h>
29#include <WebCore/ResourceHandle.h>
30#include <sys/socket.h>
31#include <wtf/RunLoop.h>
32#include <wtf/StdLibExtras.h>
33#include <wtf/text/CString.h>
34#include <wtf/text/WTFString.h>
35
36using namespace WebCore;
37
38namespace WebKit {
39
40static Vector<std::unique_ptr<char[]>> createArgsArray(const String& prefix, const String& executablePath, const String& socket, const String& pluginPath)
41{
42    ASSERT(!executablePath.isEmpty());
43    ASSERT(!socket.isEmpty());
44
45    Vector<String> splitArgs;
46    prefix.split(' ', splitArgs);
47
48    splitArgs.append(executablePath);
49    splitArgs.append(socket);
50    if (!pluginPath.isEmpty())
51        splitArgs.append(pluginPath);
52
53    Vector<std::unique_ptr<char[]>> args;
54    args.resize(splitArgs.size() + 1); // Extra room for null.
55
56    size_t numArgs = splitArgs.size();
57    for (size_t i = 0; i < numArgs; ++i) {
58        CString param = splitArgs[i].utf8();
59        args[i] = std::make_unique<char[]>(param.length() + 1); // Room for the terminating null coming from the CString.
60        strncpy(args[i].get(), param.data(), param.length() + 1); // +1 here so that strncpy copies the ending null.
61    }
62    // execvp() needs the pointers' array to be null-terminated.
63    args[numArgs] = nullptr;
64
65    return args;
66}
67
68void ProcessLauncher::launchProcess()
69{
70    int sockets[2];
71    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
72        ASSERT_NOT_REACHED();
73        return;
74    }
75
76    String processCmdPrefix, executablePath, pluginPath;
77    switch (m_launchOptions.processType) {
78    case WebProcess:
79        executablePath = executablePathOfWebProcess();
80        break;
81#if ENABLE(PLUGIN_PROCESS)
82    case PluginProcess:
83        executablePath = executablePathOfPluginProcess();
84        pluginPath = m_launchOptions.extraInitializationData.get("plugin-path");
85        break;
86#endif
87#if ENABLE(NETWORK_PROCESS)
88    case NetworkProcess:
89        executablePath = executablePathOfNetworkProcess();
90        break;
91#endif
92    default:
93        ASSERT_NOT_REACHED();
94        return;
95    }
96
97#ifndef NDEBUG
98    if (!m_launchOptions.processCmdPrefix.isEmpty())
99        processCmdPrefix = m_launchOptions.processCmdPrefix;
100#endif
101    auto args = createArgsArray(processCmdPrefix, executablePath, String::number(sockets[0]), pluginPath);
102
103    // Do not perform memory allocation in the middle of the fork()
104    // exec() below. FastMalloc can potentially deadlock because
105    // the fork() doesn't inherit the running threads.
106    pid_t pid = fork();
107    if (!pid) { // Child process.
108        close(sockets[1]);
109        execvp(args.data()[0].get(), reinterpret_cast<char* const*>(args.data()));
110    } else if (pid > 0) { // parent process;
111        close(sockets[0]);
112        m_processIdentifier = pid;
113        // We've finished launching the process, message back to the main run loop.
114        RunLoop::main().dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, pid, sockets[1]));
115    } else {
116        ASSERT_NOT_REACHED();
117        return;
118    }
119}
120
121void ProcessLauncher::terminateProcess()
122{
123    if (m_isLaunching) {
124        invalidate();
125        return;
126    }
127
128    if (!m_processIdentifier)
129        return;
130    kill(m_processIdentifier, SIGKILL);
131    m_processIdentifier = 0;
132}
133
134void ProcessLauncher::platformInvalidate()
135{
136}
137
138} // namespace WebKit
139