dom/plugins/base/nsPluginsDirUnix.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/plugins/base/nsPluginsDirUnix.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,421 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsNPAPIPlugin.h"
    1.10 +#include "nsNPAPIPluginInstance.h"
    1.11 +#include "nsIMemory.h"
    1.12 +#include "nsPluginsDir.h"
    1.13 +#include "nsPluginsDirUtils.h"
    1.14 +#include "prmem.h"
    1.15 +#include "prenv.h"
    1.16 +#include "prerror.h"
    1.17 +#include "prio.h"
    1.18 +#include <sys/stat.h>
    1.19 +#include "nsString.h"
    1.20 +#include "nsIFile.h"
    1.21 +#include "nsIPrefBranch.h"
    1.22 +#include "nsIPrefService.h"
    1.23 +
    1.24 +#define LOCAL_PLUGIN_DLL_SUFFIX ".so"
    1.25 +#if defined(__hpux)
    1.26 +#define DEFAULT_X11_PATH "/usr/lib/X11R6/"
    1.27 +#undef LOCAL_PLUGIN_DLL_SUFFIX
    1.28 +#define LOCAL_PLUGIN_DLL_SUFFIX ".sl"
    1.29 +#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so"
    1.30 +#elif defined(_AIX)
    1.31 +#define DEFAULT_X11_PATH "/usr/lib"
    1.32 +#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".a"
    1.33 +#elif defined(SOLARIS)
    1.34 +#define DEFAULT_X11_PATH "/usr/openwin/lib/"
    1.35 +#elif defined(LINUX)
    1.36 +#define DEFAULT_X11_PATH "/usr/X11R6/lib/"
    1.37 +#elif defined(__APPLE__)
    1.38 +#define DEFAULT_X11_PATH "/usr/X11R6/lib"
    1.39 +#undef LOCAL_PLUGIN_DLL_SUFFIX
    1.40 +#define LOCAL_PLUGIN_DLL_SUFFIX ".dylib"
    1.41 +#define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so"
    1.42 +#else
    1.43 +#define DEFAULT_X11_PATH ""
    1.44 +#endif
    1.45 +
    1.46 +#if (MOZ_WIDGET_GTK == 2)
    1.47 +
    1.48 +#define PLUGIN_MAX_LEN_OF_TMP_ARR 512
    1.49 +
    1.50 +static void DisplayPR_LoadLibraryErrorMessage(const char *libName)
    1.51 +{
    1.52 +    char errorMsg[PLUGIN_MAX_LEN_OF_TMP_ARR] = "Cannot get error from NSPR.";
    1.53 +    if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
    1.54 +        PR_GetErrorText(errorMsg);
    1.55 +
    1.56 +    fprintf(stderr, "LoadPlugin: failed to initialize shared library %s [%s]\n",
    1.57 +        libName, errorMsg);
    1.58 +}
    1.59 +
    1.60 +static void SearchForSoname(const char* name, char** soname)
    1.61 +{
    1.62 +    if (!(name && soname))
    1.63 +        return;
    1.64 +    PRDir *fdDir = PR_OpenDir(DEFAULT_X11_PATH);
    1.65 +    if (!fdDir)
    1.66 +        return;       
    1.67 +
    1.68 +    int n = strlen(name);
    1.69 +    PRDirEntry *dirEntry;
    1.70 +    while ((dirEntry = PR_ReadDir(fdDir, PR_SKIP_BOTH))) {
    1.71 +        if (!PL_strncmp(dirEntry->name, name, n)) {
    1.72 +            if (dirEntry->name[n] == '.' && dirEntry->name[n+1] && !dirEntry->name[n+2]) {
    1.73 +                // name.N, wild guess this is what we need
    1.74 +                char out[PLUGIN_MAX_LEN_OF_TMP_ARR] = DEFAULT_X11_PATH;
    1.75 +                PL_strcat(out, dirEntry->name);
    1.76 +                *soname = PL_strdup(out);
    1.77 +               break;
    1.78 +            }
    1.79 +        }
    1.80 +    }
    1.81 +
    1.82 +    PR_CloseDir(fdDir);
    1.83 +}
    1.84 +
    1.85 +static bool LoadExtraSharedLib(const char *name, char **soname, bool tryToGetSoname)
    1.86 +{
    1.87 +    bool ret = true;
    1.88 +    PRLibSpec tempSpec;
    1.89 +    PRLibrary *handle;
    1.90 +    tempSpec.type = PR_LibSpec_Pathname;
    1.91 +    tempSpec.value.pathname = name;
    1.92 +    handle = PR_LoadLibraryWithFlags(tempSpec, PR_LD_NOW|PR_LD_GLOBAL);
    1.93 +    if (!handle) {
    1.94 +        ret = false;
    1.95 +        DisplayPR_LoadLibraryErrorMessage(name);
    1.96 +        if (tryToGetSoname) {
    1.97 +            SearchForSoname(name, soname);
    1.98 +            if (*soname) {
    1.99 +                ret = LoadExtraSharedLib((const char *) *soname, nullptr, false);
   1.100 +            }
   1.101 +        }
   1.102 +    }
   1.103 +    return ret;
   1.104 +}
   1.105 +
   1.106 +#define PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS 32
   1.107 +#define PREF_PLUGINS_SONAME "plugin.soname.list"
   1.108 +#if defined(SOLARIS) || defined(HPUX)
   1.109 +#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX ":libXm" LOCAL_PLUGIN_DLL_SUFFIX
   1.110 +#else
   1.111 +#define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX
   1.112 +#endif
   1.113 +/*
   1.114 + this function looks for
   1.115 + user_pref("plugin.soname.list", "/usr/X11R6/lib/libXt.so.6:libXext.so");
   1.116 + in user's pref.js
   1.117 + and loads all libs in specified order
   1.118 +*/
   1.119 +
   1.120 +static void LoadExtraSharedLibs()
   1.121 +{
   1.122 +    // check out if user's prefs.js has libs name
   1.123 +    nsresult res;
   1.124 +    nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &res));
   1.125 +    if (NS_SUCCEEDED(res) && (prefs != nullptr)) {
   1.126 +        char *sonameList = nullptr;
   1.127 +        bool prefSonameListIsSet = true;
   1.128 +        res = prefs->GetCharPref(PREF_PLUGINS_SONAME, &sonameList);
   1.129 +        if (!sonameList) {
   1.130 +            // pref is not set, lets use hardcoded list
   1.131 +            prefSonameListIsSet = false;
   1.132 +            sonameList = PL_strdup(DEFAULT_EXTRA_LIBS_LIST);
   1.133 +        }
   1.134 +        if (sonameList) {
   1.135 +            char *arrayOfLibs[PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS] = {0};
   1.136 +            int numOfLibs = 0;
   1.137 +            char *nextToken;
   1.138 +            char *p = nsCRT::strtok(sonameList,":",&nextToken);
   1.139 +            if (p) {
   1.140 +                while (p && numOfLibs < PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS) {
   1.141 +                    arrayOfLibs[numOfLibs++] = p;
   1.142 +                    p = nsCRT::strtok(nextToken,":",&nextToken);
   1.143 +                }
   1.144 +            } else // there is just one lib
   1.145 +                arrayOfLibs[numOfLibs++] = sonameList;
   1.146 +
   1.147 +            char sonameListToSave[PLUGIN_MAX_LEN_OF_TMP_ARR] = "";
   1.148 +            for (int i=0; i<numOfLibs; i++) {
   1.149 +                // trim out head/tail white spaces (just in case)
   1.150 +                bool head = true;
   1.151 +                p = arrayOfLibs[i];
   1.152 +                while (*p) {
   1.153 +                    if (*p == ' ' || *p == '\t') {
   1.154 +                        if (head) {
   1.155 +                            arrayOfLibs[i] = ++p;
   1.156 +                        } else {
   1.157 +                            *p = 0;
   1.158 +                        }
   1.159 +                    } else {
   1.160 +                        head = false;
   1.161 +                        p++;
   1.162 +                    }
   1.163 +                }
   1.164 +                if (!arrayOfLibs[i][0]) {
   1.165 +                    continue; // null string
   1.166 +                }
   1.167 +                bool tryToGetSoname = true;
   1.168 +                if (PL_strchr(arrayOfLibs[i], '/')) {
   1.169 +                    //assuming it's real name, try to stat it
   1.170 +                    struct stat st;
   1.171 +                    if (stat((const char*) arrayOfLibs[i], &st)) {
   1.172 +                        //get just a file name
   1.173 +                        arrayOfLibs[i] = PL_strrchr(arrayOfLibs[i], '/') + 1;
   1.174 +                    } else
   1.175 +                        tryToGetSoname = false;
   1.176 +                }
   1.177 +                char *soname = nullptr;
   1.178 +                if (LoadExtraSharedLib(arrayOfLibs[i], &soname, tryToGetSoname)) {
   1.179 +                    //construct soname's list to save in prefs
   1.180 +                    p = soname ? soname : arrayOfLibs[i];
   1.181 +                    int n = PLUGIN_MAX_LEN_OF_TMP_ARR -
   1.182 +                        (strlen(sonameListToSave) + strlen(p));
   1.183 +                    if (n > 0) {
   1.184 +                        PL_strcat(sonameListToSave, p);
   1.185 +                        PL_strcat(sonameListToSave,":");
   1.186 +                    }
   1.187 +                    if (soname) {
   1.188 +                        PL_strfree(soname); // it's from strdup
   1.189 +                    }
   1.190 +                    if (numOfLibs > 1)
   1.191 +                        arrayOfLibs[i][strlen(arrayOfLibs[i])] = ':'; //restore ":" in sonameList
   1.192 +                }
   1.193 +            }
   1.194 +
   1.195 +            // Check whether sonameListToSave is a empty String, Bug: 329205
   1.196 +            if (sonameListToSave[0]) 
   1.197 +                for (p = &sonameListToSave[strlen(sonameListToSave) - 1]; *p == ':'; p--)
   1.198 +                    *p = 0; //delete tail ":" delimiters
   1.199 +
   1.200 +            if (!prefSonameListIsSet || PL_strcmp(sonameList, sonameListToSave)) {
   1.201 +                // if user specified some bogus soname I overwrite it here,
   1.202 +                // otherwise it'll decrease performance by calling popen() in SearchForSoname
   1.203 +                // every time for each bogus name
   1.204 +                prefs->SetCharPref(PREF_PLUGINS_SONAME, (const char *)sonameListToSave);
   1.205 +            }
   1.206 +            PL_strfree(sonameList);
   1.207 +        }
   1.208 +    }
   1.209 +}
   1.210 +#endif //MOZ_WIDGET_GTK2
   1.211 +
   1.212 +/* nsPluginsDir implementation */
   1.213 +
   1.214 +bool nsPluginsDir::IsPluginFile(nsIFile* file)
   1.215 +{
   1.216 +    nsAutoCString filename;
   1.217 +    if (NS_FAILED(file->GetNativeLeafName(filename)))
   1.218 +        return false;
   1.219 +
   1.220 +#ifdef ANDROID
   1.221 +    // It appears that if you load
   1.222 +    // 'libstagefright_honeycomb.so' on froyo, or
   1.223 +    // 'libstagefright_froyo.so' on honeycomb, we will abort.
   1.224 +    // Since these are just helper libs, we can ignore.
   1.225 +    const char *cFile = filename.get();
   1.226 +    if (strstr(cFile, "libstagefright") != nullptr)
   1.227 +        return false;
   1.228 +#endif
   1.229 +
   1.230 +    NS_NAMED_LITERAL_CSTRING(dllSuffix, LOCAL_PLUGIN_DLL_SUFFIX);
   1.231 +    if (filename.Length() > dllSuffix.Length() &&
   1.232 +        StringEndsWith(filename, dllSuffix))
   1.233 +        return true;
   1.234 +    
   1.235 +#ifdef LOCAL_PLUGIN_DLL_ALT_SUFFIX
   1.236 +    NS_NAMED_LITERAL_CSTRING(dllAltSuffix, LOCAL_PLUGIN_DLL_ALT_SUFFIX);
   1.237 +    if (filename.Length() > dllAltSuffix.Length() &&
   1.238 +        StringEndsWith(filename, dllAltSuffix))
   1.239 +        return true;
   1.240 +#endif
   1.241 +    return false;
   1.242 +}
   1.243 +
   1.244 +/* nsPluginFile implementation */
   1.245 +
   1.246 +nsPluginFile::nsPluginFile(nsIFile* file)
   1.247 +: mPlugin(file)
   1.248 +{
   1.249 +}
   1.250 +
   1.251 +nsPluginFile::~nsPluginFile()
   1.252 +{
   1.253 +}
   1.254 +
   1.255 +nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
   1.256 +{
   1.257 +    PRLibSpec libSpec;
   1.258 +    libSpec.type = PR_LibSpec_Pathname;
   1.259 +    bool exists = false;
   1.260 +    mPlugin->Exists(&exists);
   1.261 +    if (!exists)
   1.262 +        return NS_ERROR_FILE_NOT_FOUND;
   1.263 +
   1.264 +    nsresult rv;
   1.265 +    nsAutoCString path;
   1.266 +    rv = mPlugin->GetNativePath(path);
   1.267 +    if (NS_FAILED(rv))
   1.268 +        return rv;
   1.269 +
   1.270 +    libSpec.value.pathname = path.get();
   1.271 +
   1.272 +#if (MOZ_WIDGET_GTK == 2)
   1.273 +
   1.274 +    // Normally, Mozilla isn't linked against libXt and libXext
   1.275 +    // since it's a Gtk/Gdk application.  On the other hand,
   1.276 +    // legacy plug-ins expect the libXt and libXext symbols
   1.277 +    // to already exist in the global name space.  This plug-in
   1.278 +    // wrapper is linked against libXt and libXext, but since
   1.279 +    // we never call on any of these libraries, plug-ins still
   1.280 +    // fail to resolve Xt symbols when trying to do a dlopen
   1.281 +    // at runtime.  Explicitly opening Xt/Xext into the global
   1.282 +    // namespace before attempting to load the plug-in seems to
   1.283 +    // work fine.
   1.284 +
   1.285 +
   1.286 +#if defined(SOLARIS) || defined(HPUX)
   1.287 +    // Acrobat/libXm: Lazy resolving might cause crash later (bug 211587)
   1.288 +    *outLibrary = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW);
   1.289 +    pLibrary = *outLibrary;
   1.290 +#else
   1.291 +    // Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744)
   1.292 +    *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
   1.293 +    pLibrary = *outLibrary;
   1.294 +#endif
   1.295 +    if (!pLibrary) {
   1.296 +        LoadExtraSharedLibs();
   1.297 +        // try reload plugin once more
   1.298 +        *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
   1.299 +        pLibrary = *outLibrary;
   1.300 +        if (!pLibrary) {
   1.301 +            DisplayPR_LoadLibraryErrorMessage(libSpec.value.pathname);
   1.302 +            return NS_ERROR_FAILURE;
   1.303 +        }
   1.304 +    }
   1.305 +#else
   1.306 +    *outLibrary = PR_LoadLibraryWithFlags(libSpec, 0);
   1.307 +    pLibrary = *outLibrary;
   1.308 +#endif  // MOZ_WIDGET_GTK2
   1.309 +
   1.310 +#ifdef DEBUG
   1.311 +    printf("LoadPlugin() %s returned %lx\n", 
   1.312 +           libSpec.value.pathname, (unsigned long)pLibrary);
   1.313 +#endif
   1.314 +
   1.315 +    if (!pLibrary) {
   1.316 +        return NS_ERROR_FAILURE;
   1.317 +    }
   1.318 +    
   1.319 +    return NS_OK;
   1.320 +}
   1.321 +
   1.322 +nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary)
   1.323 +{
   1.324 +    *outLibrary = nullptr;
   1.325 +
   1.326 +    info.fVersion = nullptr;
   1.327 +
   1.328 +    // Sadly we have to load the library for this to work.
   1.329 +    nsresult rv = LoadPlugin(outLibrary);
   1.330 +    if (NS_FAILED(rv))
   1.331 +        return rv;
   1.332 +  
   1.333 +    const char* (*npGetPluginVersion)() =
   1.334 +        (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetPluginVersion");
   1.335 +    if (npGetPluginVersion) {
   1.336 +        info.fVersion = PL_strdup(npGetPluginVersion());
   1.337 +    }
   1.338 +
   1.339 +    const char* (*npGetMIMEDescription)() =
   1.340 +        (const char* (*)()) PR_FindFunctionSymbol(pLibrary, "NP_GetMIMEDescription");
   1.341 +    if (!npGetMIMEDescription) {
   1.342 +        return NS_ERROR_FAILURE;
   1.343 +    }
   1.344 +
   1.345 +    const char* mimedescr = npGetMIMEDescription();
   1.346 +    if (!mimedescr) {
   1.347 +        return NS_ERROR_FAILURE;
   1.348 +    }
   1.349 +
   1.350 +    rv = ParsePluginMimeDescription(mimedescr, info);
   1.351 +    if (NS_FAILED(rv)) {
   1.352 +        return rv;
   1.353 +    }
   1.354 +
   1.355 +    nsAutoCString path;
   1.356 +    if (NS_FAILED(rv = mPlugin->GetNativePath(path)))
   1.357 +        return rv;
   1.358 +    info.fFullPath = PL_strdup(path.get());
   1.359 +
   1.360 +    nsAutoCString fileName;
   1.361 +    if (NS_FAILED(rv = mPlugin->GetNativeLeafName(fileName)))
   1.362 +        return rv;
   1.363 +    info.fFileName = PL_strdup(fileName.get());
   1.364 +
   1.365 +    NP_GetValueFunc npGetValue = (NP_GetValueFunc)PR_FindFunctionSymbol(pLibrary, "NP_GetValue");
   1.366 +    if (!npGetValue) {
   1.367 +        return NS_ERROR_FAILURE;
   1.368 +    }
   1.369 +
   1.370 +    const char *name = nullptr;
   1.371 +    npGetValue(nullptr, NPPVpluginNameString, &name);
   1.372 +    if (name) {
   1.373 +        info.fName = PL_strdup(name);
   1.374 +    }
   1.375 +    else {
   1.376 +        info.fName = PL_strdup(fileName.get());
   1.377 +    }
   1.378 +
   1.379 +    const char *description = nullptr;
   1.380 +    npGetValue(nullptr, NPPVpluginDescriptionString, &description);
   1.381 +    if (description) {
   1.382 +        info.fDescription = PL_strdup(description);
   1.383 +    }
   1.384 +    else {
   1.385 +        info.fDescription = PL_strdup("");
   1.386 +    }
   1.387 +
   1.388 +    return NS_OK;
   1.389 +}
   1.390 +
   1.391 +nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info)
   1.392 +{
   1.393 +    if (info.fName != nullptr)
   1.394 +        PL_strfree(info.fName);
   1.395 +
   1.396 +    if (info.fDescription != nullptr)
   1.397 +        PL_strfree(info.fDescription);
   1.398 +
   1.399 +    for (uint32_t i = 0; i < info.fVariantCount; i++) {
   1.400 +        if (info.fMimeTypeArray[i] != nullptr)
   1.401 +            PL_strfree(info.fMimeTypeArray[i]);
   1.402 +
   1.403 +        if (info.fMimeDescriptionArray[i] != nullptr)
   1.404 +            PL_strfree(info.fMimeDescriptionArray[i]);
   1.405 +
   1.406 +        if (info.fExtensionArray[i] != nullptr)
   1.407 +            PL_strfree(info.fExtensionArray[i]);
   1.408 +    }
   1.409 +
   1.410 +    PR_FREEIF(info.fMimeTypeArray);
   1.411 +    PR_FREEIF(info.fMimeDescriptionArray);
   1.412 +    PR_FREEIF(info.fExtensionArray);
   1.413 +
   1.414 +    if (info.fFullPath != nullptr)
   1.415 +        PL_strfree(info.fFullPath);
   1.416 +
   1.417 +    if (info.fFileName != nullptr)
   1.418 +        PL_strfree(info.fFileName);
   1.419 +
   1.420 +    if (info.fVersion != nullptr)
   1.421 +        PL_strfree(info.fVersion);
   1.422 +
   1.423 +    return NS_OK;
   1.424 +}

mercurial