1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
41 UNIX implementation of the nsPluginsDir/nsPluginsFile classes.
47 #include "nsNPAPIPlugin.h"
48 #include "nsNPAPIPluginInstance.h"
49 #include "nsIServiceManager.h"
50 #include "nsIMemory.h"
51 #include "nsIPluginStreamListener.h"
52 #include "nsPluginsDir.h"
53 #include "nsPluginsDirUtils.h"
54 #include "nsObsoleteModuleLoading.h"
60 #include "nsILocalFile.h"
61 #include "nsIPrefBranch.h"
62 #include "nsIPrefService.h"
64 #include "nsPluginLogging.h"
66 #define LOG(args) PLUGIN_LOG(PLUGIN_LOG_NORMAL, args)
69 #define LOCAL_PLUGIN_DLL_SUFFIX ".so"
71 #define DEFAULT_X11_PATH "/usr/lib/X11R6/"
72 #undef LOCAL_PLUGIN_DLL_SUFFIX
73 #define LOCAL_PLUGIN_DLL_SUFFIX ".sl"
74 #define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".so"
76 #define DEFAULT_X11_PATH "/usr/lib"
77 #define LOCAL_PLUGIN_DLL_ALT_SUFFIX ".a"
78 #elif defined(SOLARIS)
79 #define DEFAULT_X11_PATH "/usr/openwin/lib/"
81 #define DEFAULT_X11_PATH "/usr/X11R6/lib/"
83 #define DEFAULT_X11_PATH ""
86 #if defined(MOZ_WIDGET_GTK2)
88 #define PLUGIN_MAX_LEN_OF_TMP_ARR 512
90 static void DisplayPR_LoadLibraryErrorMessage(const char *libName
)
92 char errorMsg
[PLUGIN_MAX_LEN_OF_TMP_ARR
] = "Cannot get error from NSPR.";
93 if (PR_GetErrorTextLength() < (int) sizeof(errorMsg
))
94 PR_GetErrorText(errorMsg
);
96 fprintf(stderr
, "LoadPlugin: failed to initialize shared library %s [%s]\n",
100 static void SearchForSoname(const char* name
, char** soname
)
102 if (!(name
&& soname
))
104 PRDir
*fdDir
= PR_OpenDir(DEFAULT_X11_PATH
);
108 int n
= PL_strlen(name
);
109 PRDirEntry
*dirEntry
;
110 while ((dirEntry
= PR_ReadDir(fdDir
, PR_SKIP_BOTH
))) {
111 if (!PL_strncmp(dirEntry
->name
, name
, n
)) {
112 if (dirEntry
->name
[n
] == '.' && dirEntry
->name
[n
+1] && !dirEntry
->name
[n
+2]) {
113 // name.N, wild guess this is what we need
114 char out
[PLUGIN_MAX_LEN_OF_TMP_ARR
] = DEFAULT_X11_PATH
;
115 PL_strcat(out
, dirEntry
->name
);
116 *soname
= PL_strdup(out
);
125 static PRBool
LoadExtraSharedLib(const char *name
, char **soname
, PRBool tryToGetSoname
)
127 PRBool ret
= PR_TRUE
;
130 tempSpec
.type
= PR_LibSpec_Pathname
;
131 tempSpec
.value
.pathname
= name
;
132 handle
= PR_LoadLibraryWithFlags(tempSpec
, PR_LD_NOW
|PR_LD_GLOBAL
);
135 DisplayPR_LoadLibraryErrorMessage(name
);
136 if (tryToGetSoname
) {
137 SearchForSoname(name
, soname
);
139 ret
= LoadExtraSharedLib((const char *) *soname
, NULL
, PR_FALSE
);
146 #define PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS 32
147 #define PREF_PLUGINS_SONAME "plugin.soname.list"
148 #if defined(SOLARIS) || defined(HPUX)
149 #define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX ":libXm" LOCAL_PLUGIN_DLL_SUFFIX
151 #define DEFAULT_EXTRA_LIBS_LIST "libXt" LOCAL_PLUGIN_DLL_SUFFIX ":libXext" LOCAL_PLUGIN_DLL_SUFFIX
154 this function looks for
155 user_pref("plugin.soname.list", "/usr/X11R6/lib/libXt.so.6:libXext.so");
157 and loads all libs in specified order
160 static void LoadExtraSharedLibs()
162 // check out if user's prefs.js has libs name
164 nsCOMPtr
<nsIPrefBranch
> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID
, &res
));
165 if (NS_SUCCEEDED(res
) && (prefs
!= nsnull
)) {
166 char *sonamesListFromPref
= PREF_PLUGINS_SONAME
;
167 char *sonameList
= NULL
;
168 PRBool prefSonameListIsSet
= PR_TRUE
;
169 res
= prefs
->GetCharPref(sonamesListFromPref
, &sonameList
);
171 // pref is not set, lets use hardcoded list
172 prefSonameListIsSet
= PR_FALSE
;
173 sonameList
= PL_strdup(DEFAULT_EXTRA_LIBS_LIST
);
176 char *arrayOfLibs
[PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS
] = {0};
179 char *p
= nsCRT::strtok(sonameList
,":",&nextToken
);
181 while (p
&& numOfLibs
< PLUGIN_MAX_NUMBER_OF_EXTRA_LIBS
) {
182 arrayOfLibs
[numOfLibs
++] = p
;
183 p
= nsCRT::strtok(nextToken
,":",&nextToken
);
185 } else // there is just one lib
186 arrayOfLibs
[numOfLibs
++] = sonameList
;
188 char sonameListToSave
[PLUGIN_MAX_LEN_OF_TMP_ARR
] = "";
189 for (int i
=0; i
<numOfLibs
; i
++) {
190 // trim out head/tail white spaces (just in case)
191 PRBool head
= PR_TRUE
;
194 if (*p
== ' ' || *p
== '\t') {
196 arrayOfLibs
[i
] = ++p
;
205 if (!arrayOfLibs
[i
][0]) {
206 continue; // null string
208 PRBool tryToGetSoname
= PR_TRUE
;
209 if (PL_strchr(arrayOfLibs
[i
], '/')) {
210 //assuming it's real name, try to stat it
212 if (stat((const char*) arrayOfLibs
[i
], &st
)) {
213 //get just a file name
214 arrayOfLibs
[i
] = PL_strrchr(arrayOfLibs
[i
], '/') + 1;
216 tryToGetSoname
= PR_FALSE
;
219 if (LoadExtraSharedLib(arrayOfLibs
[i
], &soname
, tryToGetSoname
)) {
220 //construct soname's list to save in prefs
221 p
= soname
? soname
: arrayOfLibs
[i
];
222 int n
= PLUGIN_MAX_LEN_OF_TMP_ARR
-
223 (PL_strlen(sonameListToSave
) + PL_strlen(p
));
225 PL_strcat(sonameListToSave
, p
);
226 PL_strcat(sonameListToSave
,":");
229 PL_strfree(soname
); // it's from strdup
232 arrayOfLibs
[i
][PL_strlen(arrayOfLibs
[i
])] = ':'; //restore ":" in sonameList
236 // Check whether sonameListToSave is a empty String, Bug: 329205
237 if (sonameListToSave
[0])
238 for (p
= &sonameListToSave
[PL_strlen(sonameListToSave
) - 1]; *p
== ':'; p
--)
239 *p
= 0; //delete tail ":" delimiters
241 if (!prefSonameListIsSet
|| PL_strcmp(sonameList
, sonameListToSave
)) {
242 // if user specified some bogus soname I overwrite it here,
243 // otherwise it'll decrease performance by calling popen() in SearchForSoname
244 // every time for each bogus name
245 prefs
->SetCharPref(sonamesListFromPref
, (const char *)sonameListToSave
);
247 PL_strfree(sonameList
);
251 #endif //MOZ_WIDGET_GTK2
255 ///////////////////////////////////////////////////////////////////////////
257 /* nsPluginsDir implementation */
259 PRBool
nsPluginsDir::IsPluginFile(nsIFile
* file
)
261 nsCAutoString filename
;
262 if (NS_FAILED(file
->GetNativeLeafName(filename
)))
265 NS_NAMED_LITERAL_CSTRING(dllSuffix
, LOCAL_PLUGIN_DLL_SUFFIX
);
266 if (filename
.Length() > dllSuffix
.Length() &&
267 StringEndsWith(filename
, dllSuffix
))
270 #ifdef LOCAL_PLUGIN_DLL_ALT_SUFFIX
271 NS_NAMED_LITERAL_CSTRING(dllAltSuffix
, LOCAL_PLUGIN_DLL_ALT_SUFFIX
);
272 if (filename
.Length() > dllAltSuffix
.Length() &&
273 StringEndsWith(filename
, dllAltSuffix
))
279 ///////////////////////////////////////////////////////////////////////////
281 /* nsPluginFile implementation */
283 nsPluginFile::nsPluginFile(nsIFile
* file
)
289 nsPluginFile::~nsPluginFile()
296 * This code is necessary for Java 1.4.2 SR2 and later on AIX, as the
297 * loadquery() function is no longer used to determine the path to the
298 * installed JVM, so we need to manually set the LIBPATH variable to
299 * include the proper directories needed to run the Java plug-in.
301 * See Bug 297807 for more information.
303 static char *javaLibPath
= NULL
;
305 static void SetJavaLibPath(const nsCString
& pluginPath
)
307 // If javaLibPath is non-NULL, that means we have already set the LIBPATH
308 // variable once this session, so we don't need to do it again.
312 nsCAutoString javaDir
, newLibPath
;
314 PRInt32 pos
= pluginPath
.RFindChar('/');
315 if (pos
== kNotFound
|| pos
== 0)
318 javaDir
= Substring(pluginPath
, 0, pos
);
319 LOG(("AIX: Java dir is %s\n", javaDir
.get()));
321 // Add jre/bin to new LIBPATH
322 newLibPath
+= javaDir
;
324 // Check for existance of jre/bin/classic dir, and append it to
327 javaDir
.AppendLiteral("/classic");
328 if (PR_GetFileInfo(javaDir
.get(), &info
) == PR_SUCCESS
&&
329 info
.type
== PR_FILE_DIRECTORY
)
331 newLibPath
.Append(':');
332 newLibPath
.Append(javaDir
);
335 // Get the current LIBPATH, and append it to the new LIBPATH
336 const char *currentLibPath
= PR_GetEnv("LIBPATH");
337 LOG(("AIX: current LIBPATH=%s\n", currentLibPath
));
338 if (currentLibPath
&& *currentLibPath
) {
339 newLibPath
.Append(':');
340 newLibPath
.Append(currentLibPath
);
343 // Set the LIBPATH to include the path to the JRE directories.
344 // NOTE: We are leaking javaLibPath here, as it needs to remain in memory
345 // for PR_SetEnv to work properly.
346 javaLibPath
= PR_smprintf("LIBPATH=%s", newLibPath
.get());
348 LOG(("AIX: new LIBPATH=%s\n", newLibPath
.get()));
349 PR_SetEnv(javaLibPath
);
355 * Loads the plugin into memory using NSPR's shared-library loading
356 * mechanism. Handles platform differences in loading shared libraries.
358 nsresult
nsPluginFile::LoadPlugin(PRLibrary
* &outLibrary
)
361 libSpec
.type
= PR_LibSpec_Pathname
;
362 PRBool exists
= PR_FALSE
;
363 mPlugin
->Exists(&exists
);
365 return NS_ERROR_FILE_NOT_FOUND
;
369 rv
= mPlugin
->GetNativePath(path
);
374 nsCAutoString leafName
;
375 rv
= mPlugin
->GetNativeLeafName(leafName
);
379 if (StringBeginsWith(leafName
, NS_LITERAL_CSTRING("libjavaplugin_oji")))
380 SetJavaLibPath(path
);
383 libSpec
.value
.pathname
= path
.get();
385 #if defined(MOZ_WIDGET_GTK2)
387 ///////////////////////////////////////////////////////////
388 // Normally, Mozilla isn't linked against libXt and libXext
389 // since it's a Gtk/Gdk application. On the other hand,
390 // legacy plug-ins expect the libXt and libXext symbols
391 // to already exist in the global name space. This plug-in
392 // wrapper is linked against libXt and libXext, but since
393 // we never call on any of these libraries, plug-ins still
394 // fail to resolve Xt symbols when trying to do a dlopen
395 // at runtime. Explicitly opening Xt/Xext into the global
396 // namespace before attempting to load the plug-in seems to
400 #if defined(SOLARIS) || defined(HPUX)
401 // Acrobat/libXm: Lazy resolving might cause crash later (bug 211587)
402 pLibrary
= outLibrary
= PR_LoadLibraryWithFlags(libSpec
, PR_LD_NOW
);
404 // Some dlopen() doesn't recover from a failed PR_LD_NOW (bug 223744)
405 pLibrary
= outLibrary
= PR_LoadLibraryWithFlags(libSpec
, 0);
408 LoadExtraSharedLibs();
409 // try reload plugin once more
410 pLibrary
= outLibrary
= PR_LoadLibraryWithFlags(libSpec
, 0);
412 DisplayPR_LoadLibraryErrorMessage(libSpec
.value
.pathname
);
415 pLibrary
= outLibrary
= PR_LoadLibraryWithFlags(libSpec
, 0);
416 #endif // MOZ_WIDGET_GTK2
419 printf("LoadPlugin() %s returned %lx\n",
420 libSpec
.value
.pathname
, (unsigned long)pLibrary
);
427 * Obtains all of the information currently available for this plugin.
429 nsresult
nsPluginFile::GetPluginInfo(nsPluginInfo
& info
)
432 const char* mimedescr
= 0, *name
= 0, *description
= 0;
434 // No, this doesn't leak. GetGlobalServiceManager() doesn't addref
435 // it's out pointer. Maybe it should.
436 nsIServiceManagerObsolete
* mgr
;
437 nsServiceManager::GetGlobalServiceManager((nsIServiceManager
**)&mgr
);
439 nsFactoryProc nsGetFactory
=
440 (nsFactoryProc
) PR_FindFunctionSymbol(pLibrary
, "NSGetFactory");
442 nsCOMPtr
<nsIPlugin
> plugin
;
444 info
.fVersion
= nsnull
;
446 // It's an almost-new-style plugin. The "truly new" plugins
447 // are just XPCOM components, but there are some Mozilla
448 // Classic holdovers that live in the plugins directory but
449 // implement nsIPlugin and the factory stuff.
450 static NS_DEFINE_CID(kPluginCID
, NS_PLUGIN_CID
);
452 nsCOMPtr
<nsIFactory
> factory
;
453 rv
= nsGetFactory(mgr
, kPluginCID
, nsnull
, nsnull
,
454 getter_AddRefs(factory
));
457 // HACK: The symbol lookup for "NSGetFactory" mistakenly returns
458 // a reference to an unrelated function when we have an NPAPI
459 // plugin linked to libxul.so. Give this plugin another shot as
461 rv
= nsNPAPIPlugin::CreatePlugin(0, 0, pLibrary
, getter_AddRefs(plugin
));
465 plugin
= do_QueryInterface(factory
);
469 // if fileName parameter == 0 nsNPAPIPlugin::CreatePlugin() will not call NP_Initialize()
470 rv
= nsNPAPIPlugin::CreatePlugin(0, 0, pLibrary
, getter_AddRefs(plugin
));
471 if (NS_FAILED(rv
)) return rv
;
475 const char* (*npGetPluginVersion
)() =
476 (const char* (*)()) PR_FindFunctionSymbol(pLibrary
, "NP_GetPluginVersion");
477 if (npGetPluginVersion
)
478 info
.fVersion
= PL_strdup(npGetPluginVersion());
480 plugin
->GetMIMEDescription(&mimedescr
);
482 printf("GetMIMEDescription() returned \"%s\"\n", mimedescr
);
484 if (NS_FAILED(rv
= ParsePluginMimeDescription(mimedescr
, info
)))
486 nsCAutoString filename
;
487 if (NS_FAILED(rv
= mPlugin
->GetNativePath(filename
)))
489 info
.fFileName
= PL_strdup(filename
.get());
490 plugin
->GetValue(nsPluginVariable_NameString
, &name
);
492 name
= PL_strrchr(info
.fFileName
, '/') + 1;
493 info
.fName
= PL_strdup(name
);
495 plugin
->GetValue(nsPluginVariable_DescriptionString
, &description
);
498 info
.fDescription
= PL_strdup(description
);
504 nsresult
nsPluginFile::FreePluginInfo(nsPluginInfo
& info
)
506 if (info
.fName
!= nsnull
)
507 PL_strfree(info
.fName
);
509 if (info
.fDescription
!= nsnull
)
510 PL_strfree(info
.fDescription
);
512 for (PRUint32 i
= 0; i
< info
.fVariantCount
; i
++) {
513 if (info
.fMimeTypeArray
[i
] != nsnull
)
514 PL_strfree(info
.fMimeTypeArray
[i
]);
516 if (info
.fMimeDescriptionArray
[i
] != nsnull
)
517 PL_strfree(info
.fMimeDescriptionArray
[i
]);
519 if (info
.fExtensionArray
[i
] != nsnull
)
520 PL_strfree(info
.fExtensionArray
[i
]);
523 PR_FREEIF(info
.fMimeTypeArray
);
524 PR_FREEIF(info
.fMimeDescriptionArray
);
525 PR_FREEIF(info
.fExtensionArray
);
527 if (info
.fFileName
!= nsnull
)
528 PL_strfree(info
.fFileName
);
530 if (info
.fVersion
!= nsnull
)
531 PL_strfree(info
.fVersion
);