示例#1
0
bool PluginProcessProxy::scanPlugin(const String& pluginPath, RawPluginMetaData& result)
{
    CString binaryPath = fileSystemRepresentation(executablePathOfPluginProcess());
    CString pluginPathCString = fileSystemRepresentation(pluginPath);
    char* argv[4];
    argv[0] = const_cast<char*>(binaryPath.data());
    argv[1] = const_cast<char*>("-scanPlugin");
    argv[2] = const_cast<char*>(pluginPathCString.data());
    argv[3] = 0;

    gint status;
    gchar* stdOut;
    if (!g_spawn_sync(0, argv, 0, G_SPAWN_STDERR_TO_DEV_NULL, 0, 0, &stdOut, 0, &status, 0))
        return false;
    if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS)
        return false;

    const unsigned kNumLinesExpected = 3;
    String lines[kNumLinesExpected];
    unsigned lineIndex = 0;
    const UChar* current = reinterpret_cast<const UChar*>(stdOut);
    while (lineIndex < kNumLinesExpected) {
        const UChar* start = current;
        while (*current++ != UChar('\n')) { }
        lines[lineIndex++] = String(start, current - start - 1);
    }

    result.name.swap(lines[0]);
    result.description.swap(lines[1]);
    result.mimeDescription.swap(lines[2]);
    return !result.mimeDescription.isEmpty();
}
示例#2
0
bool PluginProcessProxy::scanPlugin(const String& pluginPath, RawPluginMetaData& result)
{
    QFileInfo pluginFileInfo(pluginPath);
    if (!pluginFileInfo.exists())
        return false;

    MetaDataResult::Tag metaDataResult = tryReadPluginMetaDataFromCacheFile(pluginFileInfo.canonicalFilePath(), result);
    if (metaDataResult == MetaDataResult::Available)
        return true;
    if (metaDataResult == MetaDataResult::Unloadable)
        return false;

    // Scan the plugin via the plugin process.
    QString commandLine = QString(executablePathOfPluginProcess()) % QLatin1Char(' ')
                          % QStringLiteral("-scanPlugin") % QLatin1Char(' ') % pluginFileInfo.canonicalFilePath();
    QProcess process;
    process.setReadChannel(QProcess::StandardOutput);
    process.start(commandLine);

    bool ranSuccessfully = process.waitForFinished()
                           && process.exitStatus() == QProcess::NormalExit
                           && process.exitCode() == EXIT_SUCCESS;
    if (ranSuccessfully) {
        QByteArray outputBytes = process.readAll();
        ASSERT(!(outputBytes.size() % sizeof(UChar)));

        String output(reinterpret_cast<const UChar*>(outputBytes.constData()), outputBytes.size() / sizeof(UChar));
        Vector<String> lines;
        output.split(UChar('\n'), true, lines);
        ASSERT(lines.size() == 3);

        result.name.swap(lines[0]);
        result.description.swap(lines[1]);
        result.mimeDescription.swap(lines[2]);
    } else
        process.kill();

    QVariantMap map;
    map[QStringLiteral("path")] = QString(pluginFileInfo.canonicalFilePath());
    map[QStringLiteral("timestamp")] = QDateTime::currentDateTime().toString();

    if (!ranSuccessfully || result.mimeDescription.isEmpty()) {
        // We failed getting the meta data in some way. Cache this information, so we don't
        // need to rescan such plugins every time. We will retry it once the plugin is updated.

        map[QStringLiteral("unloadable")] = QStringLiteral("true");
        appendToCacheFile(QJsonObject::fromVariantMap(map));
        return false;
    }

    map[QStringLiteral("name")] = QString(result.name);
    map[QStringLiteral("description")] = QString(result.description);
    map[QStringLiteral("mimeDescription")] = QString(result.mimeDescription);
    appendToCacheFile(QJsonObject::fromVariantMap(map));
    return true;
}
bool PluginProcessProxy::scanPlugin(const String& pluginPath, RawPluginMetaData& result)
{
#if PLATFORM(GTK) || PLATFORM(EFL)
    CString binaryPath = fileSystemRepresentation(executablePathOfPluginProcess());
    CString pluginPathCString = fileSystemRepresentation(pluginPath);
    char* argv[4];
    argv[0] = const_cast<char*>(binaryPath.data());
    argv[1] = const_cast<char*>("-scanPlugin");
    argv[2] = const_cast<char*>(pluginPathCString.data());
    argv[3] = 0;

    int status;
    GUniqueOutPtr<char> stdOut;

    // If the disposition of SIGCLD signal is set to SIG_IGN (default)
    // then the signal will be ignored and g_spawn_sync() will not be
    // able to return the status.
    // As a consequence, we make sure that the disposition is set to
    // SIG_DFL before calling g_spawn_sync().
#if defined(SIGCLD)
    struct sigaction action;
    sigaction(SIGCLD, 0, &action);
    if (action.sa_handler == SIG_IGN) {
        action.sa_handler = SIG_DFL;
        sigaction(SIGCLD, &action, 0);
    }
#endif

    if (!g_spawn_sync(0, argv, 0, G_SPAWN_STDERR_TO_DEV_NULL, 0, 0, &stdOut.outPtr(), 0, &status, 0))
        return false;

    if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS || !stdOut)
        return false;

    String stdOutString = String::fromUTF8(stdOut.get());

    Vector<String> lines;
    stdOutString.split(UChar('\n'), true, lines);

    if (lines.size() < 3)
        return false;

    result.name.swap(lines[0]);
    result.description.swap(lines[1]);
    result.mimeDescription.swap(lines[2]);
#if PLATFORM(GTK)
    if (lines.size() > 3)
        result.requiresGtk2 = lines[3] == "requires-gtk2";
#endif
    return !result.mimeDescription.isEmpty();
#else // PLATFORM(GTK) || PLATFORM(EFL)
    return false;
#endif // PLATFORM(GTK) || PLATFORM(EFL)
}
示例#4
0
bool PluginProcessProxy::scanPlugin(const String& pluginPath, RawPluginMetaData& result)
{
#if PLATFORM(GTK) || (PLATFORM(EFL) && ENABLE(GLIB_SUPPORT))
    CString binaryPath = fileSystemRepresentation(executablePathOfPluginProcess());
    CString pluginPathCString = fileSystemRepresentation(pluginPath);
    char* argv[4];
    argv[0] = const_cast<char*>(binaryPath.data());
    argv[1] = const_cast<char*>("-scanPlugin");
    argv[2] = const_cast<char*>(pluginPathCString.data());
    argv[3] = 0;

    int status;
    char* stdOut = 0;

    // If the disposition of SIGCLD signal is set to SIG_IGN (default)
    // then the signal will be ignored and g_spawn_sync() will not be
    // able to return the status.
    // As a consequence, we make sure that the disposition is set to
    // SIG_DFL before calling g_spawn_sync().
    struct sigaction action;
    sigaction(SIGCLD, 0, &action);
    if (action.sa_handler == SIG_IGN) {
        action.sa_handler = SIG_DFL;
        sigaction(SIGCLD, &action, 0);
    }

    if (!g_spawn_sync(0, argv, 0, G_SPAWN_STDERR_TO_DEV_NULL, 0, 0, &stdOut, 0, &status, 0))
        return false;

    if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS || !stdOut) {
        free(stdOut);
        return false;
    }

    String stdOutString(reinterpret_cast<const UChar*>(stdOut));
    free(stdOut);

    Vector<String> lines;
    stdOutString.split(UChar('\n'), lines);

    if (lines.size() < 3)
        return false;

    result.name.swap(lines[0]);
    result.description.swap(lines[1]);
    result.mimeDescription.swap(lines[2]);
    return !result.mimeDescription.isEmpty();
#else // PLATFORM(GTK) || (PLATFORM(EFL) && ENABLE(GLIB_SUPPORT))
    return false;
#endif // PLATFORM(GTK) || (PLATFORM(EFL) && ENABLE(GLIB_SUPPORT))
}
示例#5
0
void ProcessLauncher::launchProcess()
{
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
        ASSERT_NOT_REACHED();
        return;
    }

    pid_t pid = fork();
    if (!pid) { // child process
        close(sockets[1]);
        String socket = String::format("%d", sockets[0]);
        String executablePath;
        switch (m_launchOptions.processType) {
        case WebProcess:
            executablePath = executablePathOfWebProcess();
            break;
        case PluginProcess:
            executablePath = executablePathOfPluginProcess();
            break;
        default:
            ASSERT_NOT_REACHED();
            return;
        }

#ifndef NDEBUG
        if (m_launchOptions.processCmdPrefix.isEmpty())
#endif
            execl(executablePath.utf8().data(), executablePath.utf8().data(), socket.utf8().data(), static_cast<char*>(0));
#ifndef NDEBUG
        else {
            String cmd = makeString(m_launchOptions.processCmdPrefix, ' ', executablePath, ' ', socket);
            if (system(cmd.utf8().data()) == -1) {
                ASSERT_NOT_REACHED();
                return;
            }
        }
#endif
    } 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.
        RunLoop::main()->dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, pid, sockets[1]));
    } else {
        ASSERT_NOT_REACHED();
        return;
    }
}
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 WebProcess:
        executablePath = executablePathOfWebProcess();
        break;
#if ENABLE(PLUGIN_PROCESS)
    case PluginProcess:
        executablePath = executablePathOfPluginProcess();
        pluginPath = m_launchOptions.extraInitializationData.get("plugin-path");
        break;
#endif
    default:
        ASSERT_NOT_REACHED();
        return;
    }

#ifndef NDEBUG
    if (!m_launchOptions.processCmdPrefix.isEmpty())
        processCmdPrefix = m_launchOptions.processCmdPrefix;
#endif
    Vector<OwnArrayPtr<char>> args = createArgsArray(processCmdPrefix, executablePath, String::number(sockets[0]), pluginPath);

    // 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.
        RunLoop::main()->dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, pid, sockets[1]));
    } else {
        ASSERT_NOT_REACHED();
        return;
    }
}
示例#7
0
void ProcessLauncher::launchProcess()
{
    GPid pid = 0;

    int sockets[2];
    if (socketpair(AF_UNIX, SOCKET_TYPE, 0, sockets) < 0) {
        g_printerr("Creation of socket failed: %s.\n", g_strerror(errno));
        ASSERT_NOT_REACHED();
        return;
    }

    String executablePath, pluginPath;
    CString realExecutablePath, realPluginPath;
    if (m_launchOptions.processType == WebProcess)
        executablePath = executablePathOfWebProcess();
    else {
        executablePath = executablePathOfPluginProcess();
        pluginPath = m_launchOptions.extraInitializationData.get("plugin-path");
        realPluginPath = fileSystemRepresentation(pluginPath);
    }

    realExecutablePath = fileSystemRepresentation(executablePath);
    GOwnPtr<gchar> socket(g_strdup_printf("%d", sockets[0]));
    char* argv[4];
    argv[0] = const_cast<char*>(realExecutablePath.data());
    argv[1] = socket.get();
    argv[2] = const_cast<char*>(realPluginPath.data());
    argv[3] = 0;

    GOwnPtr<GError> error;
    int spawnFlags = G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD;
    if (!g_spawn_async(0, argv, 0, static_cast<GSpawnFlags>(spawnFlags), childSetupFunction, GINT_TO_POINTER(sockets[1]), &pid, &error.outPtr())) {
        g_printerr("Unable to fork a new WebProcess: %s.\n", error->message);
        ASSERT_NOT_REACHED();
    }

    close(sockets[0]);
    m_processIdentifier = pid;

    // Monitor the child process, it calls waitpid to prevent the child process from becomming a zombie,
    // and it allows us to close the socket when the child process crashes.
    g_child_watch_add(m_processIdentifier, childFinishedFunction, GINT_TO_POINTER(sockets[1]));

    // We've finished launching the process, message back to the main run loop.
    RunLoop::main()->dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, m_processIdentifier, sockets[1]));
}
bool PluginProcessProxy::scanPlugin(const String& pluginPath, RawPluginMetaData& result)
{
#if PLATFORM(GTK) || PLATFORM(EFL)
    String pluginProcessPath = executablePathOfPluginProcess();

#if PLATFORM(GTK)
    bool requiresGtk2 = pluginRequiresGtk2(pluginPath);
    if (requiresGtk2)
#if ENABLE(PLUGIN_PROCESS_GTK2)
        pluginProcessPath.append('2');
#else
        return false;
#endif
#endif

    CString binaryPath = fileSystemRepresentation(pluginProcessPath);
    CString pluginPathCString = fileSystemRepresentation(pluginPath);
    char* argv[4];
    argv[0] = const_cast<char*>(binaryPath.data());
    argv[1] = const_cast<char*>("-scanPlugin");
    argv[2] = const_cast<char*>(pluginPathCString.data());
    argv[3] = nullptr;

    // If the disposition of SIGCLD signal is set to SIG_IGN (default)
    // then the signal will be ignored and g_spawn_sync() will not be
    // able to return the status.
    // As a consequence, we make sure that the disposition is set to
    // SIG_DFL before calling g_spawn_sync().
#if defined(SIGCLD)
    struct sigaction action;
    sigaction(SIGCLD, 0, &action);
    if (action.sa_handler == SIG_IGN) {
        action.sa_handler = SIG_DFL;
        sigaction(SIGCLD, &action, 0);
    }
#endif

    int status;
    GUniqueOutPtr<char> stdOut;
    GUniqueOutPtr<GError> error;
    if (!g_spawn_sync(nullptr, argv, nullptr, G_SPAWN_STDERR_TO_DEV_NULL, nullptr, nullptr, &stdOut.outPtr(), nullptr, &status, &error.outPtr())) {
        WTFLogAlways("Failed to launch %s: %s", argv[0], error->message);
        return false;
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS) {
        WTFLogAlways("Error scanning plugin %s, %s returned %d exit status", argv[2], argv[0], status);
        return false;
    }

    if (!stdOut) {
        WTFLogAlways("Error scanning plugin %s, %s didn't write any output to stdout", argv[2], argv[0]);
        return false;
    }

    Vector<String> lines;
    String::fromUTF8(stdOut.get()).split(UChar('\n'), true, lines);

    if (lines.size() < 3) {
        WTFLogAlways("Error scanning plugin %s, too few lines of output provided", argv[2]);
        return false;
    }

    result.name.swap(lines[0]);
    result.description.swap(lines[1]);
    result.mimeDescription.swap(lines[2]);
#if PLATFORM(GTK)
    result.requiresGtk2 = requiresGtk2;
#endif
    return !result.mimeDescription.isEmpty();
#else // PLATFORM(GTK) || PLATFORM(EFL)
    return false;
#endif // PLATFORM(GTK) || PLATFORM(EFL)
}
示例#9
0
void ProcessLauncher::launchProcess()
{
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
        ASSERT_NOT_REACHED();
        return;
    }

    CString executablePath, pluginPath;
    switch (m_launchOptions.processType) {
    case WebProcess:
        executablePath = executablePathOfWebProcess().utf8();
        break;
#if ENABLE(PLUGIN_PROCESS)
    case PluginProcess:
        executablePath = executablePathOfPluginProcess().utf8();
        pluginPath = m_launchOptions.extraInitializationData.get("plugin-path").utf8();
        break;
#endif
    default:
        ASSERT_NOT_REACHED();
        return;
    }

    char socket[5];
    snprintf(socket, sizeof(socket), "%d", sockets[0]);

#ifndef NDEBUG
    CString prefixedExecutablePath;
    if (!m_launchOptions.processCmdPrefix.isEmpty()) {
        String prefixedExecutablePathStr = m_launchOptions.processCmdPrefix + ' ' +
            String::fromUTF8(executablePath.data()) + ' ' + socket + ' ' + String::fromUTF8(pluginPath.data());
        prefixedExecutablePath = prefixedExecutablePathStr.utf8();
    }
#endif

    // 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]);
#ifndef NDEBUG
        if (!prefixedExecutablePath.isNull()) {
            // FIXME: This is not correct because it invokes the shell
            // and keeps this process waiting. Should be changed to
            // something like execvp().
            if (system(prefixedExecutablePath.data()) == -1) {
                ASSERT_NOT_REACHED();
                exit(EXIT_FAILURE);
            } else
                exit(EXIT_SUCCESS);
        }
#endif
        execl(executablePath.data(), executablePath.data(), socket, pluginPath.data(), static_cast<char*>(0));
    } 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.
        RunLoop::main()->dispatch(bind(&ProcessLauncher::didFinishLaunchingProcess, this, pid, sockets[1]));
    } else {
        ASSERT_NOT_REACHED();
        return;
    }
}