1 /*****************************************************************************
2 * bank.c : Modules list
3 *****************************************************************************
4 * Copyright (C) 2001-2011 VLC authors and VideoLAN
6 * Authors: Sam Hocevar <sam@zoy.org>
7 * Ethan C. Baldridge <BaldridgeE@cadmus.com>
8 * Hans-Peter Jansen <hpj@urpla.net>
9 * Gildas Bazin <gbazin@videolan.org>
10 * RĂ©mi Denis-Courmont
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
36 #include <sys/types.h>
42 #include <vlc_common.h>
43 #include <vlc_plugin.h>
44 #include <vlc_modules.h>
47 #include "config/configuration.h"
48 #include "modules/modules.h"
55 } modules
= { VLC_STATIC_MUTEX
, NULL
, 0 };
57 /*****************************************************************************
59 *****************************************************************************/
60 #ifdef HAVE_DYNAMIC_PLUGINS
61 static void AllocateAllPlugins (vlc_object_t
*);
63 static module_t
*module_InitStatic (vlc_plugin_cb
);
65 static void module_StoreBank (module_t
*module
)
67 /*vlc_assert_locked (&modules.lock);*/
68 module
->next
= modules
.head
;
69 modules
.head
= module
;
72 #if defined(__ELF__) || !HAVE_DYNAMIC_PLUGINS
76 # pragma weak vlc_static_modules
78 extern vlc_plugin_cb vlc_static_modules
[];
80 static void module_InitStaticModules(void)
82 if (!vlc_static_modules
)
85 for (unsigned i
= 0; vlc_static_modules
[i
]; i
++) {
86 module_t
*module
= module_InitStatic (vlc_static_modules
[i
]);
87 if (likely(module
!= NULL
))
88 module_StoreBank (module
);
92 static void module_InitStaticModules(void) { }
98 * Creates a module bank structure which will be filled later
99 * on with all the modules found.
101 void module_InitBank (void)
103 vlc_mutex_lock (&modules
.lock
);
105 if (modules
.usage
== 0)
107 /* Fills the module bank structure with the main module infos.
108 * This is very useful as it will allow us to consider the main
109 * library just as another module, and for instance the configuration
110 * options of main will be available in the module bank structure just
111 * as for every other module. */
112 module_t
*module
= module_InitStatic (vlc_entry__main
);
113 if (likely(module
!= NULL
))
114 module_StoreBank (module
);
115 config_SortConfig ();
119 /* We do retain the module bank lock until the plugins are loaded as well.
120 * This is ugly, this staged loading approach is needed: LibVLC gets
121 * some configuration parameters relevant to loading the plugins from
122 * the main (builtin) module. The module bank becomes shared read-only data
123 * once it is ready, so we need to fully serialize initialization.
124 * DO NOT UNCOMMENT the following line unless you managed to squeeze
125 * module_LoadPlugins() before you unlock the mutex. */
126 /*vlc_mutex_unlock (&modules.lock);*/
130 * Unloads all unused plugin modules and empties the module
131 * bank in case of success.
133 void module_EndBank (bool b_plugins
)
135 module_t
*head
= NULL
;
137 /* If plugins were _not_ loaded, then the caller still has the bank lock
138 * from module_InitBank(). */
140 vlc_mutex_lock (&modules
.lock
);
142 vlc_assert_locked (&modules.lock); not for static mutexes :( */
144 assert (modules
.usage
> 0);
145 if (--modules
.usage
== 0)
147 config_UnsortConfig ();
151 vlc_mutex_unlock (&modules
.lock
);
155 module_t
*module
= head
;
158 #ifdef HAVE_DYNAMIC_PLUGINS
159 if (module
->b_loaded
&& module
->b_unloadable
)
161 module_Unload (module
->handle
);
162 module
->b_loaded
= false;
165 vlc_module_destroy (module
);
169 #undef module_LoadPlugins
171 * Loads module descriptions for all available plugins.
172 * Fills the module bank structure with the plugin modules.
174 * \param p_this vlc object structure
175 * \return total number of modules in bank after loading all plug-ins
177 size_t module_LoadPlugins (vlc_object_t
*obj
)
179 /*vlc_assert_locked (&modules.lock); not for static mutexes :( */
181 if (modules
.usage
== 1)
183 module_InitStaticModules ();
184 #ifdef HAVE_DYNAMIC_PLUGINS
185 msg_Dbg (obj
, "searching plug-in modules");
186 AllocateAllPlugins (obj
);
188 config_UnsortConfig ();
189 config_SortConfig ();
191 vlc_mutex_unlock (&modules
.lock
);
194 module_t
**list
= module_list_get (&count
);
195 module_list_free (list
);
196 msg_Dbg (obj
, "plug-ins loaded: %zu modules", count
);
201 * Frees the flat list of VLC modules.
202 * @param list list obtained by module_list_get()
203 * @param length number of items on the list
206 void module_list_free (module_t
**list
)
212 * Gets the flat list of VLC modules.
213 * @param n [OUT] pointer to the number of modules
214 * @return table of module pointers (release with module_list_free()),
215 * or NULL in case of error (in that case, *n is zeroed).
217 module_t
**module_list_get (size_t *n
)
219 module_t
**tab
= NULL
;
224 for (module_t
*mod
= modules
.head
; mod
; mod
= mod
->next
)
227 nt
= realloc (tab
, (i
+ 1 + mod
->submodule_count
) * sizeof (*tab
));
228 if (unlikely(nt
== NULL
))
237 for (module_t
*subm
= mod
->submodule
; subm
; subm
= subm
->next
)
244 static int modulecmp (const void *a
, const void *b
)
246 const module_t
*const *ma
= a
, *const *mb
= b
;
247 /* Note that qsort() uses _ascending_ order,
248 * so the smallest module is the one with the biggest score. */
249 return (*mb
)->i_score
- (*ma
)->i_score
;
253 * Builds a sorted list of all VLC modules with a given capability.
254 * The list is sorted from the highest module score to the lowest.
255 * @param list pointer to the table of modules [OUT]
256 * @param cap capability of modules to look for
257 * @return the number of matching found, or -1 on error (*list is then NULL).
258 * @note *list must be freed with module_list_free().
260 ssize_t
module_list_cap (module_t
***restrict list
, const char *cap
)
262 /* TODO: This is quite inefficient. List should be sorted by capability. */
265 assert (list
!= NULL
);
267 for (module_t
*mod
= modules
.head
; mod
!= NULL
; mod
= mod
->next
)
269 if (module_provides (mod
, cap
))
271 for (module_t
*subm
= mod
->submodule
; subm
!= NULL
; subm
= subm
->next
)
272 if (module_provides (subm
, cap
))
276 module_t
**tab
= malloc (sizeof (*tab
) * n
);
278 if (unlikely(tab
== NULL
))
281 for (module_t
*mod
= modules
.head
; mod
!= NULL
; mod
= mod
->next
)
283 if (module_provides (mod
, cap
))
285 for (module_t
*subm
= mod
->submodule
; subm
!= NULL
; subm
= subm
->next
)
286 if (module_provides (subm
, cap
))
290 assert (tab
== *list
+ n
);
291 qsort (*list
, n
, sizeof (*tab
), modulecmp
);
295 #ifdef HAVE_DYNAMIC_PLUGINS
296 typedef enum { CACHE_USE
, CACHE_RESET
, CACHE_IGNORE
} cache_mode_t
;
298 static void AllocatePluginPath (vlc_object_t
*, const char *, cache_mode_t
);
301 * Enumerates all dynamic plug-ins that can be found.
303 * This function will recursively browse the default plug-ins directory and any
304 * directory listed in the VLC_PLUGIN_PATH environment variable.
305 * For performance reasons, a cache is normally used so that plug-in shared
306 * objects do not need to loaded and linked into the process.
308 static void AllocateAllPlugins (vlc_object_t
*p_this
)
313 if( !var_InheritBool( p_this
, "plugins-cache" ) )
315 else if( var_InheritBool( p_this
, "reset-plugins-cache" ) )
320 #ifdef WINAPI_FAMILY_APP
321 /* Windows Store Apps can not load external plugins with absolute paths. */
322 AllocatePluginPath (p_this
, "plugins", mode
);
324 /* Contruct the special search path for system that have a relocatable
325 * executable. Set it to <vlc path>/plugins. */
326 char *vlcpath
= config_GetLibDir ();
327 if (likely(vlcpath
!= NULL
)
328 && likely(asprintf (&paths
, "%s" DIR_SEP
"plugins", vlcpath
) != -1))
330 AllocatePluginPath (p_this
, paths
, mode
);
334 #endif /* WINAPI_FAMILY_APP */
336 /* If the user provided a plugin path, we add it to the list */
337 paths
= getenv( "VLC_PLUGIN_PATH" );
341 paths
= strdup( paths
); /* don't harm the environment ! :) */
342 if( unlikely(paths
== NULL
) )
345 for( char *buf
, *path
= strtok_r( paths
, PATH_SEP
, &buf
);
347 path
= strtok_r( NULL
, PATH_SEP
, &buf
) )
348 AllocatePluginPath (p_this
, path
, mode
);
353 typedef struct module_bank
360 module_cache_t
*cache
;
363 module_cache_t
*loaded_cache
;
366 static void AllocatePluginDir (module_bank_t
*, unsigned,
367 const char *, const char *);
370 * Scans for plug-ins within a file system hierarchy.
371 * \param path base directory to browse
373 static void AllocatePluginPath (vlc_object_t
*p_this
, const char *path
,
377 module_cache_t
*cache
= NULL
;
383 count
= CacheLoad( p_this
, path
, &cache
);
386 CacheDelete( p_this
, path
);
389 msg_Dbg( p_this
, "ignoring plugins cache file" );
392 msg_Dbg( p_this
, "recursively browsing `%s'", path
);
399 bank
.loaded_cache
= cache
;
400 bank
.i_loaded_cache
= count
;
402 /* Don't go deeper than 5 subdirectories */
403 AllocatePluginDir (&bank
, 5, path
, NULL
);
408 /* Discard unmatched cache entries */
409 for( size_t i
= 0; i
< count
; i
++ )
411 if (cache
[i
].p_module
!= NULL
)
412 vlc_module_destroy (cache
[i
].p_module
);
413 free (cache
[i
].path
);
417 CacheSave (p_this
, path
, bank
.cache
, bank
.i_cache
);
423 static int AllocatePluginFile (module_bank_t
*, const char *,
424 const char *, const struct stat
*);
427 * Recursively browses a directory to look for plug-ins.
429 static void AllocatePluginDir (module_bank_t
*bank
, unsigned maxdepth
,
430 const char *absdir
, const char *reldir
)
436 DIR *dh
= vlc_opendir (absdir
);
440 /* Parse the directory and try to load all files it contains. */
443 char *file
= vlc_readdir (dh
), *relpath
= NULL
, *abspath
= NULL
;
448 if (!strcmp (file
, ".") || !strcmp (file
, ".."))
451 /* Compute path relative to plug-in base directory */
454 if (asprintf (&relpath
, "%s"DIR_SEP
"%s", reldir
, file
) == -1)
458 relpath
= strdup (file
);
459 if (unlikely(relpath
== NULL
))
462 /* Compute absolute path */
463 if (asprintf (&abspath
, "%s"DIR_SEP
"%s", bank
->base
, relpath
) == -1)
470 if (vlc_stat (abspath
, &st
) == -1)
473 if (S_ISREG (st
.st_mode
))
475 static const char prefix
[] = "lib";
476 static const char suffix
[] = "_plugin"LIBEXT
;
477 size_t len
= strlen (file
);
480 /* Check that file matches the "lib*_plugin"LIBEXT pattern */
481 if (len
> strlen (suffix
)
482 && !strncmp (file
, prefix
, strlen (prefix
))
483 && !strcmp (file
+ len
- strlen (suffix
), suffix
))
485 /* We load all the files ending with LIBEXT on OS/2,
486 * because OS/2 has a 8.3 length limitation for DLL name */
487 if (len
> strlen (LIBEXT
)
488 && !strcasecmp (file
+ len
- strlen (LIBEXT
), LIBEXT
))
490 AllocatePluginFile (bank
, abspath
, relpath
, &st
);
492 else if (S_ISDIR (st
.st_mode
))
493 /* Recurse into another directory */
494 AllocatePluginDir (bank
, maxdepth
, abspath
, relpath
);
503 static module_t
*module_InitDynamic (vlc_object_t
*, const char *, bool);
506 * Scans a plug-in from a file.
508 static int AllocatePluginFile (module_bank_t
*bank
, const char *abspath
,
509 const char *relpath
, const struct stat
*st
)
511 module_t
*module
= NULL
;
513 /* Check our plugins cache first then load plugin if needed */
514 if (bank
->mode
== CACHE_USE
)
516 module
= CacheFind (bank
->loaded_cache
, bank
->i_loaded_cache
,
520 module
->psz_filename
= strdup (abspath
);
521 if (unlikely(module
->psz_filename
== NULL
))
523 vlc_module_destroy (module
);
529 module
= module_InitDynamic (bank
->obj
, abspath
, true);
533 /* We have not already scanned and inserted this module */
534 assert (module
->next
== NULL
);
536 /* Unload plugin until we really need it */
537 if (module
->b_loaded
&& module
->b_unloadable
)
539 module_Unload (module
->handle
);
540 module
->b_loaded
= false;
543 /* For now we force loading if the module's config contains callbacks.
544 * Could be optimized by adding an API call.*/
545 for (size_t n
= module
->confsize
, i
= 0; i
< n
; i
++)
546 if (module
->p_config
[i
].list_count
== 0
547 && (module
->p_config
[i
].list
.psz_cb
!= NULL
|| module
->p_config
[i
].list
.i_cb
!= NULL
))
549 /* !unloadable not allowed for plugins with callbacks */
550 vlc_module_destroy (module
);
551 module
= module_InitDynamic (bank
->obj
, abspath
, false);
552 if (unlikely(module
== NULL
))
557 module_StoreBank (module
);
559 if (bank
->mode
!= CACHE_IGNORE
) /* Add entry to cache */
560 CacheAdd (&bank
->cache
, &bank
->i_cache
, relpath
, st
, module
);
561 /* TODO: deal with errors */
566 # define EXTERN_PREFIX "_"
568 # define EXTERN_PREFIX
573 * Loads a dynamically-linked plug-in into memory and initialize it.
575 * The module can then be handled by module_need() and module_unneed().
577 * \param path file path of the shared object
578 * \param fast whether to optimize loading for speed or safety
579 * (fast is used when the plug-in is registered but not used)
581 static module_t
*module_InitDynamic (vlc_object_t
*obj
, const char *path
,
584 module_handle_t handle
;
586 if (module_Load (obj
, path
, &handle
, fast
))
589 /* Try to resolve the symbol */
590 static const char entry_name
[] = EXTERN_PREFIX
"vlc_entry" MODULE_SUFFIX
;
591 vlc_plugin_cb entry
=
592 (vlc_plugin_cb
) module_Lookup (handle
, entry_name
);
595 msg_Warn (obj
, "cannot find plug-in entry point in %s", path
);
599 /* We can now try to call the symbol */
600 module_t
*module
= vlc_plugin_describe (entry
);
601 if (unlikely(module
== NULL
))
603 /* With a well-written module we shouldn't have to print an
604 * additional error message here, but just make sure. */
605 msg_Err (obj
, "cannot initialize plug-in %s", path
);
609 module
->psz_filename
= strdup (path
);
610 if (unlikely(module
->psz_filename
== NULL
))
612 vlc_module_destroy (module
);
615 module
->handle
= handle
;
616 module
->b_loaded
= true;
619 module_Unload( handle
);
622 #endif /* HAVE_DYNAMIC_PLUGINS */
625 * Registers a statically-linked plug-in.
627 static module_t
*module_InitStatic (vlc_plugin_cb entry
)
629 /* Initializes the module */
630 module_t
*module
= vlc_plugin_describe (entry
);
631 if (unlikely(module
== NULL
))
634 module
->b_loaded
= true;
635 module
->b_unloadable
= false;
640 * Makes sure the module is loaded in memory.
641 * \return 0 on success, -1 on failure
643 int module_Map (vlc_object_t
*obj
, module_t
*module
)
645 if (module
->parent
!= NULL
)
646 module
= module
->parent
;
648 #warning FIXME: race condition!
649 if (module
->b_loaded
)
651 assert (module
->psz_filename
!= NULL
);
653 #ifdef HAVE_DYNAMIC_PLUGINS
654 module_t
*uncache
= module_InitDynamic (obj
, module
->psz_filename
, false);
657 CacheMerge (obj
, module
, uncache
);
658 vlc_module_destroy (uncache
);
662 msg_Err (obj
, "corrupt module: %s", module
->psz_filename
);