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>
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
42 #include <vlc_modules.h>
45 #include "config/configuration.h"
46 #include "modules/modules.h"
53 } modules
= { VLC_STATIC_MUTEX
, NULL
, 0 };
55 /*****************************************************************************
57 *****************************************************************************/
58 #ifdef HAVE_DYNAMIC_PLUGINS
59 static void AllocateAllPlugins (vlc_object_t
*);
61 static module_t
*module_InitStatic (vlc_plugin_cb
);
63 static void module_StoreBank (module_t
*module
)
65 /*vlc_assert_locked (&modules.lock);*/
66 module
->next
= modules
.head
;
67 modules
.head
= module
;
70 #if defined(__ELF__) || !HAVE_DYNAMIC_PLUGINS
74 # pragma weak vlc_static_modules
76 extern vlc_plugin_cb vlc_static_modules
[];
78 static void module_InitStaticModules(void)
80 if (!vlc_static_modules
)
83 for (unsigned i
= 0; vlc_static_modules
[i
]; i
++) {
84 module_t
*module
= module_InitStatic (vlc_static_modules
[i
]);
85 if (likely(module
!= NULL
))
86 module_StoreBank (module
);
90 static void module_InitStaticModules(void) { }
96 * Creates a module bank structure which will be filled later
97 * on with all the modules found.
99 void module_InitBank (void)
101 vlc_mutex_lock (&modules
.lock
);
103 if (modules
.usage
== 0)
105 /* Fills the module bank structure with the core module infos.
106 * This is very useful as it will allow us to consider the core
107 * library just as another module, and for instance the configuration
108 * options of core will be available in the module bank structure just
109 * as for every other module. */
110 module_t
*module
= module_InitStatic (vlc_entry__core
);
111 if (likely(module
!= NULL
))
112 module_StoreBank (module
);
113 config_SortConfig ();
117 /* We do retain the module bank lock until the plugins are loaded as well.
118 * This is ugly, this staged loading approach is needed: LibVLC gets
119 * some configuration parameters relevant to loading the plugins from
120 * the core (builtin) module. The module bank becomes shared read-only data
121 * once it is ready, so we need to fully serialize initialization.
122 * DO NOT UNCOMMENT the following line unless you managed to squeeze
123 * module_LoadPlugins() before you unlock the mutex. */
124 /*vlc_mutex_unlock (&modules.lock);*/
128 * Unloads all unused plugin modules and empties the module
129 * bank in case of success.
131 void module_EndBank (bool b_plugins
)
133 module_t
*head
= NULL
;
135 /* If plugins were _not_ loaded, then the caller still has the bank lock
136 * from module_InitBank(). */
138 vlc_mutex_lock (&modules
.lock
);
140 vlc_assert_locked (&modules.lock); not for static mutexes :( */
142 assert (modules
.usage
> 0);
143 if (--modules
.usage
== 0)
145 config_UnsortConfig ();
149 vlc_mutex_unlock (&modules
.lock
);
153 module_t
*module
= head
;
156 #ifdef HAVE_DYNAMIC_PLUGINS
157 if (module
->b_loaded
&& module
->b_unloadable
)
159 module_Unload (module
->handle
);
160 module
->b_loaded
= false;
163 vlc_module_destroy (module
);
167 #undef module_LoadPlugins
169 * Loads module descriptions for all available plugins.
170 * Fills the module bank structure with the plugin modules.
172 * \param p_this vlc object structure
173 * \return total number of modules in bank after loading all plug-ins
175 size_t module_LoadPlugins (vlc_object_t
*obj
)
177 /*vlc_assert_locked (&modules.lock); not for static mutexes :( */
179 if (modules
.usage
== 1)
181 module_InitStaticModules ();
182 #ifdef HAVE_DYNAMIC_PLUGINS
183 msg_Dbg (obj
, "searching plug-in modules");
184 AllocateAllPlugins (obj
);
186 config_UnsortConfig ();
187 config_SortConfig ();
189 vlc_mutex_unlock (&modules
.lock
);
192 module_t
**list
= module_list_get (&count
);
193 module_list_free (list
);
194 msg_Dbg (obj
, "plug-ins loaded: %zu modules", count
);
199 * Frees the flat list of VLC modules.
200 * @param list list obtained by module_list_get()
201 * @param length number of items on the list
204 void module_list_free (module_t
**list
)
210 * Gets the flat list of VLC modules.
211 * @param n [OUT] pointer to the number of modules
212 * @return table of module pointers (release with module_list_free()),
213 * or NULL in case of error (in that case, *n is zeroed).
215 module_t
**module_list_get (size_t *n
)
217 module_t
**tab
= NULL
;
222 for (module_t
*mod
= modules
.head
; mod
; mod
= mod
->next
)
225 nt
= realloc (tab
, (i
+ 1 + mod
->submodule_count
) * sizeof (*tab
));
226 if (unlikely(nt
== NULL
))
235 for (module_t
*subm
= mod
->submodule
; subm
; subm
= subm
->next
)
242 static int modulecmp (const void *a
, const void *b
)
244 const module_t
*const *ma
= a
, *const *mb
= b
;
245 /* Note that qsort() uses _ascending_ order,
246 * so the smallest module is the one with the biggest score. */
247 return (*mb
)->i_score
- (*ma
)->i_score
;
251 * Builds a sorted list of all VLC modules with a given capability.
252 * The list is sorted from the highest module score to the lowest.
253 * @param list pointer to the table of modules [OUT]
254 * @param cap capability of modules to look for
255 * @return the number of matching found, or -1 on error (*list is then NULL).
256 * @note *list must be freed with module_list_free().
258 ssize_t
module_list_cap (module_t
***restrict list
, const char *cap
)
260 /* TODO: This is quite inefficient. List should be sorted by capability. */
263 assert (list
!= NULL
);
265 for (module_t
*mod
= modules
.head
; mod
!= NULL
; mod
= mod
->next
)
267 if (module_provides (mod
, cap
))
269 for (module_t
*subm
= mod
->submodule
; subm
!= NULL
; subm
= subm
->next
)
270 if (module_provides (subm
, cap
))
274 module_t
**tab
= malloc (sizeof (*tab
) * n
);
276 if (unlikely(tab
== NULL
))
279 for (module_t
*mod
= modules
.head
; mod
!= NULL
; mod
= mod
->next
)
281 if (module_provides (mod
, cap
))
283 for (module_t
*subm
= mod
->submodule
; subm
!= NULL
; subm
= subm
->next
)
284 if (module_provides (subm
, cap
))
288 assert (tab
== *list
+ n
);
289 qsort (*list
, n
, sizeof (*tab
), modulecmp
);
293 #ifdef HAVE_DYNAMIC_PLUGINS
294 typedef enum { CACHE_USE
, CACHE_RESET
, CACHE_IGNORE
} cache_mode_t
;
296 static void AllocatePluginPath (vlc_object_t
*, const char *, cache_mode_t
);
299 * Enumerates all dynamic plug-ins that can be found.
301 * This function will recursively browse the default plug-ins directory and any
302 * directory listed in the VLC_PLUGIN_PATH environment variable.
303 * For performance reasons, a cache is normally used so that plug-in shared
304 * objects do not need to loaded and linked into the process.
306 static void AllocateAllPlugins (vlc_object_t
*p_this
)
311 if( !var_InheritBool( p_this
, "plugins-cache" ) )
313 else if( var_InheritBool( p_this
, "reset-plugins-cache" ) )
319 /* Windows Store Apps can not load external plugins with absolute paths. */
320 AllocatePluginPath (p_this
, "plugins", mode
);
322 /* Contruct the special search path for system that have a relocatable
323 * executable. Set it to <vlc path>/plugins. */
324 char *vlcpath
= config_GetLibDir ();
325 if (likely(vlcpath
!= NULL
)
326 && likely(asprintf (&paths
, "%s" DIR_SEP
"plugins", vlcpath
) != -1))
328 AllocatePluginPath (p_this
, paths
, mode
);
332 #endif /* VLC_WINSTORE_APP */
334 /* If the user provided a plugin path, we add it to the list */
335 paths
= getenv( "VLC_PLUGIN_PATH" );
339 paths
= strdup( paths
); /* don't harm the environment ! :) */
340 if( unlikely(paths
== NULL
) )
343 for( char *buf
, *path
= strtok_r( paths
, PATH_SEP
, &buf
);
345 path
= strtok_r( NULL
, PATH_SEP
, &buf
) )
346 AllocatePluginPath (p_this
, path
, mode
);
351 typedef struct module_bank
358 module_cache_t
*cache
;
361 module_cache_t
*loaded_cache
;
364 static void AllocatePluginDir (module_bank_t
*, unsigned,
365 const char *, const char *);
368 * Scans for plug-ins within a file system hierarchy.
369 * \param path base directory to browse
371 static void AllocatePluginPath (vlc_object_t
*p_this
, const char *path
,
375 module_cache_t
*cache
= NULL
;
381 count
= CacheLoad( p_this
, path
, &cache
);
384 CacheDelete( p_this
, path
);
387 msg_Dbg( p_this
, "ignoring plugins cache file" );
390 msg_Dbg( p_this
, "recursively browsing `%s'", path
);
397 bank
.loaded_cache
= cache
;
398 bank
.i_loaded_cache
= count
;
400 /* Don't go deeper than 5 subdirectories */
401 AllocatePluginDir (&bank
, 5, path
, NULL
);
406 /* Discard unmatched cache entries */
407 for( size_t i
= 0; i
< count
; i
++ )
409 if (cache
[i
].p_module
!= NULL
)
410 vlc_module_destroy (cache
[i
].p_module
);
411 free (cache
[i
].path
);
415 CacheSave (p_this
, path
, bank
.cache
, bank
.i_cache
);
421 static int AllocatePluginFile (module_bank_t
*, const char *,
422 const char *, const struct stat
*);
425 * Recursively browses a directory to look for plug-ins.
427 static void AllocatePluginDir (module_bank_t
*bank
, unsigned maxdepth
,
428 const char *absdir
, const char *reldir
)
434 DIR *dh
= vlc_opendir (absdir
);
438 /* Parse the directory and try to load all files it contains. */
441 char *file
= vlc_readdir (dh
), *relpath
= NULL
, *abspath
= NULL
;
446 if (!strcmp (file
, ".") || !strcmp (file
, ".."))
449 /* Compute path relative to plug-in base directory */
452 if (asprintf (&relpath
, "%s"DIR_SEP
"%s", reldir
, file
) == -1)
456 relpath
= strdup (file
);
457 if (unlikely(relpath
== NULL
))
460 /* Compute absolute path */
461 if (asprintf (&abspath
, "%s"DIR_SEP
"%s", bank
->base
, relpath
) == -1)
468 if (vlc_stat (abspath
, &st
) == -1)
471 if (S_ISREG (st
.st_mode
))
473 static const char prefix
[] = "lib";
474 static const char suffix
[] = "_plugin"LIBEXT
;
475 size_t len
= strlen (file
);
478 /* Check that file matches the "lib*_plugin"LIBEXT pattern */
479 if (len
> strlen (suffix
)
480 && !strncmp (file
, prefix
, strlen (prefix
))
481 && !strcmp (file
+ len
- strlen (suffix
), suffix
))
483 /* We load all the files ending with LIBEXT on OS/2,
484 * because OS/2 has a 8.3 length limitation for DLL name */
485 if (len
> strlen (LIBEXT
)
486 && !strcasecmp (file
+ len
- strlen (LIBEXT
), LIBEXT
))
488 AllocatePluginFile (bank
, abspath
, relpath
, &st
);
490 else if (S_ISDIR (st
.st_mode
))
491 /* Recurse into another directory */
492 AllocatePluginDir (bank
, maxdepth
, abspath
, relpath
);
500 static module_t
*module_InitDynamic (vlc_object_t
*, const char *, bool);
503 * Scans a plug-in from a file.
505 static int AllocatePluginFile (module_bank_t
*bank
, const char *abspath
,
506 const char *relpath
, const struct stat
*st
)
508 module_t
*module
= NULL
;
510 /* Check our plugins cache first then load plugin if needed */
511 if (bank
->mode
== CACHE_USE
)
513 module
= CacheFind (bank
->loaded_cache
, bank
->i_loaded_cache
,
517 module
->psz_filename
= strdup (abspath
);
518 if (unlikely(module
->psz_filename
== NULL
))
520 vlc_module_destroy (module
);
526 module
= module_InitDynamic (bank
->obj
, abspath
, true);
530 /* We have not already scanned and inserted this module */
531 assert (module
->next
== NULL
);
533 /* Unload plugin until we really need it */
534 if (module
->b_loaded
&& module
->b_unloadable
)
536 module_Unload (module
->handle
);
537 module
->b_loaded
= false;
540 /* For now we force loading if the module's config contains callbacks.
541 * Could be optimized by adding an API call.*/
542 for (size_t n
= module
->confsize
, i
= 0; i
< n
; i
++)
543 if (module
->p_config
[i
].list_count
== 0
544 && (module
->p_config
[i
].list
.psz_cb
!= NULL
|| module
->p_config
[i
].list
.i_cb
!= NULL
))
546 /* !unloadable not allowed for plugins with callbacks */
547 vlc_module_destroy (module
);
548 module
= module_InitDynamic (bank
->obj
, abspath
, false);
549 if (unlikely(module
== NULL
))
554 module_StoreBank (module
);
556 if (bank
->mode
!= CACHE_IGNORE
) /* Add entry to cache */
557 CacheAdd (&bank
->cache
, &bank
->i_cache
, relpath
, st
, module
);
558 /* TODO: deal with errors */
563 # define EXTERN_PREFIX "_"
565 # define EXTERN_PREFIX
570 * Loads a dynamically-linked plug-in into memory and initialize it.
572 * The module can then be handled by module_need() and module_unneed().
574 * \param path file path of the shared object
575 * \param fast whether to optimize loading for speed or safety
576 * (fast is used when the plug-in is registered but not used)
578 static module_t
*module_InitDynamic (vlc_object_t
*obj
, const char *path
,
581 module_handle_t handle
;
583 if (module_Load (obj
, path
, &handle
, fast
))
586 /* Try to resolve the symbol */
587 static const char entry_name
[] = EXTERN_PREFIX
"vlc_entry" MODULE_SUFFIX
;
588 vlc_plugin_cb entry
=
589 (vlc_plugin_cb
) module_Lookup (handle
, entry_name
);
592 msg_Warn (obj
, "cannot find plug-in entry point in %s", path
);
596 /* We can now try to call the symbol */
597 module_t
*module
= vlc_plugin_describe (entry
);
598 if (unlikely(module
== NULL
))
600 /* With a well-written module we shouldn't have to print an
601 * additional error message here, but just make sure. */
602 msg_Err (obj
, "cannot initialize plug-in %s", path
);
606 module
->psz_filename
= strdup (path
);
607 if (unlikely(module
->psz_filename
== NULL
))
609 vlc_module_destroy (module
);
612 module
->handle
= handle
;
613 module
->b_loaded
= true;
616 module_Unload( handle
);
619 #endif /* HAVE_DYNAMIC_PLUGINS */
622 * Registers a statically-linked plug-in.
624 static module_t
*module_InitStatic (vlc_plugin_cb entry
)
626 /* Initializes the module */
627 module_t
*module
= vlc_plugin_describe (entry
);
628 if (unlikely(module
== NULL
))
631 module
->b_loaded
= true;
632 module
->b_unloadable
= false;
637 * Makes sure the module is loaded in memory.
638 * \return 0 on success, -1 on failure
640 int module_Map (vlc_object_t
*obj
, module_t
*module
)
642 if (module
->parent
!= NULL
)
643 module
= module
->parent
;
645 #warning FIXME: race condition!
646 if (module
->b_loaded
)
648 assert (module
->psz_filename
!= NULL
);
650 #ifdef HAVE_DYNAMIC_PLUGINS
651 module_t
*uncache
= module_InitDynamic (obj
, module
->psz_filename
, false);
654 CacheMerge (obj
, module
, uncache
);
655 vlc_module_destroy (uncache
);
659 msg_Err (obj
, "corrupt module: %s", module
->psz_filename
);