1/*
2 * Copyright (C) 2011, 2014 Igalia S.L.
3 * Copyright (C) 2011 Apple Inc.
4 * Copyright (C) 2012 Samsung Electronics
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 * THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "config.h"
29#include "PluginProcessProxy.h"
30
31#if ENABLE(PLUGIN_PROCESS)
32
33#include "PluginProcessCreationParameters.h"
34#include "ProcessExecutablePath.h"
35#include <WebCore/PlatformDisplay.h>
36#include <sys/wait.h>
37#include <wtf/FileSystem.h>
38#include <wtf/text/CString.h>
39#include <wtf/text/WTFString.h>
40
41#if PLATFORM(GTK)
42#include <glib.h>
43#include <wtf/glib/GUniquePtr.h>
44#endif
45
46#if PLATFORM(GTK)
47#include "Module.h"
48#endif
49
50namespace WebKit {
51using namespace WebCore;
52
53void PluginProcessProxy::platformGetLaunchOptionsWithAttributes(ProcessLauncher::LaunchOptions& launchOptions, const PluginProcessAttributes& pluginProcessAttributes)
54{
55 launchOptions.processType = ProcessLauncher::ProcessType::Plugin64;
56
57 launchOptions.extraInitializationData.add("plugin-path", pluginProcessAttributes.moduleInfo.path);
58#if PLATFORM(GTK)
59 if (pluginProcessAttributes.moduleInfo.requiresGtk2)
60 launchOptions.extraInitializationData.add("requires-gtk2", emptyString());
61#endif
62}
63
64void PluginProcessProxy::platformInitializePluginProcess(PluginProcessCreationParameters&)
65{
66}
67
68#if PLATFORM(GTK)
69static bool pluginRequiresGtk2(const String& pluginPath)
70{
71 std::unique_ptr<Module> module = std::make_unique<Module>(pluginPath);
72 if (!module->load())
73 return false;
74 return module->functionPointer<gpointer>("gtk_object_get_type");
75}
76#endif
77
78#if PLUGIN_ARCHITECTURE(UNIX)
79bool PluginProcessProxy::scanPlugin(const String& pluginPath, RawPluginMetaData& result)
80{
81 String pluginProcessPath = executablePathOfPluginProcess();
82
83#if PLATFORM(GTK)
84 bool requiresGtk2 = pluginRequiresGtk2(pluginPath);
85 if (requiresGtk2) {
86#if PLATFORM(WAYLAND)
87 if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::Wayland)
88 return false;
89#endif
90#if ENABLE(PLUGIN_PROCESS_GTK2)
91 pluginProcessPath.append('2');
92 if (!FileSystem::fileExists(pluginProcessPath))
93 return false;
94#else
95 return false;
96#endif
97 }
98#endif
99
100 CString binaryPath = FileSystem::fileSystemRepresentation(pluginProcessPath);
101 CString pluginPathCString = FileSystem::fileSystemRepresentation(pluginPath);
102 char* argv[4];
103 argv[0] = const_cast<char*>(binaryPath.data());
104 argv[1] = const_cast<char*>("-scanPlugin");
105 argv[2] = const_cast<char*>(pluginPathCString.data());
106 argv[3] = nullptr;
107
108 // If the disposition of SIGCLD signal is set to SIG_IGN (default)
109 // then the signal will be ignored and g_spawn_sync() will not be
110 // able to return the status.
111 // As a consequence, we make sure that the disposition is set to
112 // SIG_DFL before calling g_spawn_sync().
113#if defined(SIGCLD)
114 struct sigaction action;
115 sigaction(SIGCLD, 0, &action);
116 if (action.sa_handler == SIG_IGN) {
117 action.sa_handler = SIG_DFL;
118 sigaction(SIGCLD, &action, 0);
119 }
120#endif
121
122 int status;
123 GUniqueOutPtr<char> stdOut;
124 GUniqueOutPtr<GError> error;
125 if (!g_spawn_sync(nullptr, argv, nullptr, G_SPAWN_STDERR_TO_DEV_NULL, nullptr, nullptr, &stdOut.outPtr(), nullptr, &status, &error.outPtr())) {
126 WTFLogAlways("Failed to launch %s: %s", argv[0], error->message);
127 return false;
128 }
129
130 if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS) {
131 WTFLogAlways("Error scanning plugin %s, %s returned %d exit status", argv[2], argv[0], status);
132 return false;
133 }
134
135 if (!stdOut) {
136 WTFLogAlways("Error scanning plugin %s, %s didn't write any output to stdout", argv[2], argv[0]);
137 return false;
138 }
139
140 Vector<String> lines = String::fromUTF8(stdOut.get()).splitAllowingEmptyEntries('\n');
141
142 if (lines.size() < 3) {
143 WTFLogAlways("Error scanning plugin %s, too few lines of output provided", argv[2]);
144 return false;
145 }
146
147 result.name.swap(lines[0]);
148 result.description.swap(lines[1]);
149 result.mimeDescription.swap(lines[2]);
150#if PLATFORM(GTK)
151 result.requiresGtk2 = requiresGtk2;
152#endif
153 return !result.mimeDescription.isEmpty();
154}
155#endif // PLUGIN_ARCHITECTURE(UNIX)
156
157} // namespace WebKit
158
159#endif // ENABLE(PLUGIN_PROCESS)
160