1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY MOTOROLA INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "ProcessLauncher.h"
29
30#include "Connection.h"
31#include "ProcessExecutablePath.h"
32#include <WebCore/AuthenticationChallenge.h>
33#include <WebCore/FileSystem.h>
34#include <WebCore/NetworkingContext.h>
35#include <WebCore/ResourceHandle.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <glib.h>
39#include <locale.h>
40#include <wtf/RunLoop.h>
41#include <wtf/text/CString.h>
42#include <wtf/text/WTFString.h>
43#include <wtf/gobject/GUniquePtr.h>
44#include <wtf/gobject/GlibUtilities.h>
45
46using namespace WebCore;
47
48namespace WebKit {
49
50static void childSetupFunction(gpointer userData)
51{
52    int socket = GPOINTER_TO_INT(userData);
53    close(socket);
54}
55
56void ProcessLauncher::launchProcess()
57{
58    GPid pid = 0;
59
60    IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection(IPC::Connection::ConnectionOptions::SetCloexecOnServer);
61
62    String executablePath, pluginPath;
63    CString realExecutablePath, realPluginPath;
64    switch (m_launchOptions.processType) {
65    case WebProcess:
66        executablePath = executablePathOfWebProcess();
67        break;
68    case PluginProcess:
69        executablePath = executablePathOfPluginProcess();
70        if (m_launchOptions.extraInitializationData.contains("requires-gtk2"))
71            executablePath.append('2');
72        pluginPath = m_launchOptions.extraInitializationData.get("plugin-path");
73        realPluginPath = fileSystemRepresentation(pluginPath);
74        break;
75#if ENABLE(NETWORK_PROCESS)
76    case NetworkProcess:
77        executablePath = executablePathOfNetworkProcess();
78        break;
79#endif
80    default:
81        ASSERT_NOT_REACHED();
82        return;
83    }
84
85    realExecutablePath = fileSystemRepresentation(executablePath);
86    GUniquePtr<gchar> socket(g_strdup_printf("%d", socketPair.client));
87
88    unsigned nargs = 4; // size of the argv array for g_spawn_async()
89
90#ifndef NDEBUG
91    Vector<CString> prefixArgs;
92    if (!m_launchOptions.processCmdPrefix.isNull()) {
93        Vector<String> splitArgs;
94        m_launchOptions.processCmdPrefix.split(' ', splitArgs);
95        for (auto it = splitArgs.begin(); it != splitArgs.end(); it++)
96            prefixArgs.append(it->utf8());
97        nargs += prefixArgs.size();
98    }
99#endif
100
101    char** argv = g_newa(char*, nargs);
102    unsigned i = 0;
103#ifndef NDEBUG
104    // If there's a prefix command, put it before the rest of the args.
105    for (auto it = prefixArgs.begin(); it != prefixArgs.end(); it++)
106        argv[i++] = const_cast<char*>(it->data());
107#endif
108    argv[i++] = const_cast<char*>(realExecutablePath.data());
109    argv[i++] = socket.get();
110    argv[i++] = const_cast<char*>(realPluginPath.data());
111    argv[i++] = 0;
112
113    GUniqueOutPtr<GError> error;
114    if (!g_spawn_async(0, argv, 0, G_SPAWN_LEAVE_DESCRIPTORS_OPEN, childSetupFunction, GINT_TO_POINTER(socketPair.server), &pid, &error.outPtr())) {
115        g_printerr("Unable to fork a new WebProcess: %s.\n", error->message);
116        ASSERT_NOT_REACHED();
117    }
118
119    // Don't expose the parent socket to potential future children.
120    while (fcntl(socketPair.client, F_SETFD, FD_CLOEXEC) == -1)
121        RELEASE_ASSERT(errno != EINTR);
122
123    close(socketPair.client);
124    m_processIdentifier = pid;
125
126    // We've finished launching the process, message back to the main run loop.
127    RunLoop::main().dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, m_processIdentifier, socketPair.server));
128}
129
130void ProcessLauncher::terminateProcess()
131{
132    if (m_isLaunching) {
133        invalidate();
134        return;
135    }
136
137    if (!m_processIdentifier)
138        return;
139
140    kill(m_processIdentifier, SIGKILL);
141    m_processIdentifier = 0;
142}
143
144void ProcessLauncher::platformInvalidate()
145{
146}
147
148} // namespace WebKit
149