]> git.sesse.net Git - vlc/blob - src/modules/modules.c
Inline DeleteModule() and simplify
[vlc] / src / modules / modules.c
1 /*****************************************************************************
2  * modules.c : Builtin and plugin modules management functions
3  *****************************************************************************
4  * Copyright (C) 2001-2011 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sam Hocevar <sam@zoy.org>
8  *          Ethan C. Baldridge <BaldridgeE@cadmus.com>
9  *          Hans-Peter Jansen <hpj@urpla.net>
10  *          Gildas Bazin <gbazin@videolan.org>
11  *          RĂ©mi Denis-Courmont
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_memory.h>
35 #include <vlc_modules.h>
36 #include "libvlc.h"
37
38 #include <stdlib.h>                                      /* free(), strtol() */
39 #include <stdio.h>                                              /* sprintf() */
40 #include <string.h>                                              /* strdup() */
41 #include <assert.h>
42
43 #include <sys/types.h>
44 #ifdef HAVE_SYS_STAT_H
45 #   include <sys/stat.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #   include <unistd.h>
49 #endif
50 #ifdef ENABLE_NLS
51 # include <libintl.h>
52 #endif
53
54 #include "config/configuration.h"
55
56 #include <vlc_fs.h>
57 #include "vlc_arrays.h"
58
59 #include "modules/modules.h"
60
61 static struct
62 {
63     vlc_mutex_t lock;
64     module_t *head;
65     unsigned usage;
66 } modules = { VLC_STATIC_MUTEX, NULL, 0 };
67
68 module_t *vlc_entry__main (void);
69
70 /*****************************************************************************
71  * Local prototypes
72  *****************************************************************************/
73 #ifdef HAVE_DYNAMIC_PLUGINS
74 typedef enum { CACHE_USE, CACHE_RESET, CACHE_IGNORE } cache_mode_t;
75 typedef struct module_bank module_bank_t;
76
77 static void AllocateAllPlugins (vlc_object_t *);
78 static void AllocatePluginPath (vlc_object_t *, const char *, cache_mode_t);
79 static void AllocatePluginDir( vlc_object_t *, module_bank_t *, const char *,
80                                unsigned, cache_mode_t );
81 static int  AllocatePluginFile( vlc_object_t *, module_bank_t *, const char *,
82                                 const struct stat *, cache_mode_t );
83 static module_t *module_InitDynamic (vlc_object_t *, const char *, bool);
84 #endif
85 static module_t *module_InitStatic (vlc_plugin_cb);
86
87 /**
88  * Init bank
89  *
90  * Creates a module bank structure which will be filled later
91  * on with all the modules found.
92  */
93 void module_InitBank (void)
94 {
95     vlc_mutex_lock (&modules.lock);
96
97     if (modules.usage == 0)
98     {
99         /* Fills the module bank structure with the main module infos.
100          * This is very useful as it will allow us to consider the main
101          * library just as another module, and for instance the configuration
102          * options of main will be available in the module bank structure just
103          * as for every other module. */
104         module_InitStatic (vlc_entry__main);
105         vlc_rwlock_init (&config_lock);
106         config_SortConfig ();
107     }
108     modules.usage++;
109
110     /* We do retain the module bank lock until the plugins are loaded as well.
111      * This is ugly, this staged loading approach is needed: LibVLC gets
112      * some configuration parameters relevant to loading the plugins from
113      * the main (builtin) module. The module bank becomes shared read-only data
114      * once it is ready, so we need to fully serialize initialization.
115      * DO NOT UNCOMMENT the following line unless you managed to squeeze
116      * module_LoadPlugins() before you unlock the mutex. */
117     /*vlc_mutex_unlock (&modules.lock);*/
118 }
119
120 /**
121  * Unloads all unused plugin modules and empties the module
122  * bank in case of success.
123  */
124 void module_EndBank (bool b_plugins)
125 {
126     module_t *head = NULL;
127
128     /* If plugins were _not_ loaded, then the caller still has the bank lock
129      * from module_InitBank(). */
130     if( b_plugins )
131         vlc_mutex_lock (&modules.lock);
132     /*else
133         vlc_assert_locked (&modules.lock); not for static mutexes :( */
134
135     assert (modules.usage > 0);
136     if (--modules.usage == 0)
137     {
138         config_UnsortConfig ();
139         vlc_rwlock_destroy (&config_lock);
140         head = modules.head;
141         modules.head = NULL;
142     }
143     vlc_mutex_unlock (&modules.lock);
144
145     while (head != NULL)
146     {
147         module_t *module = head;
148
149         head = module->next;
150 #ifdef HAVE_DYNAMIC_PLUGINS
151         if (module->b_loaded && module->b_unloadable)
152         {
153             module_Unload (module->handle);
154             module->b_loaded = false;
155         }
156 #endif
157         vlc_module_destroy (module);
158     }
159 }
160
161 #undef module_LoadPlugins
162 /**
163  * Loads module descriptions for all available plugins.
164  * Fills the module bank structure with the plugin modules.
165  *
166  * \param p_this vlc object structure
167  * \return nothing
168  */
169 void module_LoadPlugins (vlc_object_t *obj)
170 {
171     /*vlc_assert_locked (&modules.lock); not for static mutexes :( */
172
173 #ifdef HAVE_DYNAMIC_PLUGINS
174     if (modules.usage == 1)
175     {
176         msg_Dbg (obj, "searching plug-in modules");
177         AllocateAllPlugins (obj);
178         config_UnsortConfig ();
179         config_SortConfig ();
180     }
181 #endif
182     vlc_mutex_unlock (&modules.lock);
183 }
184
185 /**
186  * Checks whether a module implements a capability.
187  *
188  * \param m the module
189  * \param cap the capability to check
190  * \return TRUE if the module have the capability
191  */
192 bool module_provides( const module_t *m, const char *cap )
193 {
194     if (unlikely(m->psz_capability == NULL))
195         return false;
196     return !strcmp( m->psz_capability, cap );
197 }
198
199 /**
200  * Get the internal name of a module
201  *
202  * \param m the module
203  * \return the module name
204  */
205 const char *module_get_object( const module_t *m )
206 {
207     if (unlikely(m->i_shortcuts == 0))
208         return "unnamed";
209     return m->pp_shortcuts[0];
210 }
211
212 /**
213  * Get the human-friendly name of a module.
214  *
215  * \param m the module
216  * \param long_name TRUE to have the long name of the module
217  * \return the short or long name of the module
218  */
219 const char *module_get_name( const module_t *m, bool long_name )
220 {
221     if( long_name && ( m->psz_longname != NULL) )
222         return m->psz_longname;
223
224     if (m->psz_shortname != NULL)
225         return m->psz_shortname;
226     return module_get_object (m);
227 }
228
229 /**
230  * Get the help for a module
231  *
232  * \param m the module
233  * \return the help
234  */
235 const char *module_get_help( const module_t *m )
236 {
237     return m->psz_help;
238 }
239
240 /**
241  * Get the capability for a module
242  *
243  * \param m the module
244  * return the capability
245  */
246 const char *module_get_capability( const module_t *m )
247 {
248     return m->psz_capability;
249 }
250
251 /**
252  * Get the score for a module
253  *
254  * \param m the module
255  * return the score for the capability
256  */
257 int module_get_score( const module_t *m )
258 {
259     return m->i_score;
260 }
261
262 /**
263  * Translate a string using the module's text domain
264  *
265  * \param m the module
266  * \param str the American English ASCII string to localize
267  * \return the gettext-translated string
268  */
269 const char *module_gettext (const module_t *m, const char *str)
270 {
271     if (m->parent != NULL)
272         m = m->parent;
273     if (unlikely(str == NULL || *str == '\0'))
274         return "";
275 #ifdef ENABLE_NLS
276     const char *domain = m->domain;
277     return dgettext ((domain != NULL) ? domain : PACKAGE_NAME, str);
278 #else
279     (void)m;
280     return str;
281 #endif
282 }
283
284 #undef module_start
285 int module_start (vlc_object_t *obj, const module_t *m)
286 {
287    int (*activate) (vlc_object_t *) = m->pf_activate;
288
289    return (activate != NULL) ? activate (obj) : VLC_SUCCESS;
290 }
291
292 #undef module_stop
293 void module_stop (vlc_object_t *obj, const module_t *m)
294 {
295    void (*deactivate) (vlc_object_t *) = m->pf_deactivate;
296
297     if (deactivate != NULL)
298         deactivate (obj);
299 }
300
301 /**
302  * Frees the flat list of VLC modules.
303  * @param list list obtained by module_list_get()
304  * @param length number of items on the list
305  * @return nothing.
306  */
307 void module_list_free (module_t **list)
308 {
309     free (list);
310 }
311
312 /**
313  * Gets the flat list of VLC modules.
314  * @param n [OUT] pointer to the number of modules or NULL
315  * @return NULL-terminated table of module pointers
316  *         (release with module_list_free()), or NULL in case of error.
317  */
318 module_t **module_list_get (size_t *n)
319 {
320     /* TODO: this whole module lookup is quite inefficient */
321     /* Remove this and improve module_need */
322     module_t **tab = NULL;
323     size_t i = 0;
324
325     for (module_t *mod = modules.head; mod; mod = mod->next)
326     {
327          module_t **nt;
328          nt  = realloc (tab, (i + 2 + mod->submodule_count) * sizeof (*tab));
329          if (nt == NULL)
330          {
331              module_list_free (tab);
332              return NULL;
333          }
334
335          tab = nt;
336          tab[i++] = mod;
337          for (module_t *subm = mod->submodule; subm; subm = subm->next)
338              tab[i++] = subm;
339          tab[i] = NULL;
340     }
341     if (n != NULL)
342         *n = i;
343     return tab;
344 }
345
346 typedef struct module_list_t
347 {
348     module_t *p_module;
349     int16_t  i_score;
350     bool     b_force;
351 } module_list_t;
352
353 static int modulecmp (const void *a, const void *b)
354 {
355     const module_list_t *la = a, *lb = b;
356     /* Note that qsort() uses _ascending_ order,
357      * so the smallest module is the one with the biggest score. */
358     return lb->i_score - la->i_score;
359 }
360
361 #undef vlc_module_load
362 /**
363  * Finds and instantiates the best module of a certain type.
364  * All candidates modules having the specified capability and name will be
365  * sorted in decreasing order of priority. Then the probe callback will be
366  * invoked for each module, until it succeeds (returns 0), or all candidate
367  * module failed to initialize.
368  *
369  * The probe callback first parameter is the address of the module entry point.
370  * Further parameters are passed as an argument list; it corresponds to the
371  * variable arguments passed to this function. This scheme is meant to
372  * support arbitrary prototypes for the module entry point.
373  *
374  * \param p_this VLC object
375  * \param psz_capability capability, i.e. class of module
376  * \param psz_name name name of the module asked, if any
377  * \param b_strict if true, do not fallback to plugin with a different name
378  *                 but the same capability
379  * \param probe module probe callback
380  * \return the module or NULL in case of a failure
381  */
382 module_t *vlc_module_load(vlc_object_t *p_this, const char *psz_capability,
383                           const char *psz_name, bool b_strict,
384                           vlc_activate_t probe, ...)
385 {
386     stats_TimerStart( p_this, "module_need()", STATS_TIMER_MODULE_NEED );
387
388     module_list_t *p_list;
389     module_t *p_module;
390     int i_shortcuts = 0;
391     char *psz_shortcuts = NULL, *psz_var = NULL, *psz_alias = NULL;
392     bool b_force_backup = p_this->b_force;
393
394     /* Deal with variables */
395     if( psz_name && psz_name[0] == '$' )
396     {
397         psz_name = psz_var = var_CreateGetString( p_this, psz_name + 1 );
398     }
399
400     /* Count how many different shortcuts were asked for */
401     if( psz_name && *psz_name )
402     {
403         char *psz_parser, *psz_last_shortcut;
404
405         /* If the user wants none, give him none. */
406         if( !strcmp( psz_name, "none" ) )
407         {
408             free( psz_var );
409             stats_TimerStop( p_this, STATS_TIMER_MODULE_NEED );
410             stats_TimerDump( p_this, STATS_TIMER_MODULE_NEED );
411             stats_TimerClean( p_this, STATS_TIMER_MODULE_NEED );
412             return NULL;
413         }
414
415         i_shortcuts++;
416         psz_parser = psz_shortcuts = psz_last_shortcut = strdup( psz_name );
417
418         while( ( psz_parser = strchr( psz_parser, ',' ) ) )
419         {
420              *psz_parser = '\0';
421              i_shortcuts++;
422              psz_last_shortcut = ++psz_parser;
423         }
424
425         /* Check if the user wants to override the "strict" mode */
426         if( psz_last_shortcut )
427         {
428             if( !strcmp(psz_last_shortcut, "none") )
429             {
430                 b_strict = true;
431                 i_shortcuts--;
432             }
433             else if( !strcmp(psz_last_shortcut, "any") )
434             {
435                 b_strict = false;
436                 i_shortcuts--;
437             }
438         }
439     }
440
441     /* Sort the modules and test them */
442     size_t count;
443     module_t **p_all = module_list_get (&count);
444     p_list = malloc( count * sizeof( module_list_t ) );
445
446     /* Parse the module list for capabilities and probe each of them */
447     count = 0;
448     for (size_t i = 0; (p_module = p_all[i]) != NULL; i++)
449     {
450         int i_shortcut_bonus = 0;
451
452         /* Test that this module can do what we need */
453         if( !module_provides( p_module, psz_capability ) )
454             continue;
455
456         /* If we required a shortcut, check this plugin provides it. */
457         if( i_shortcuts > 0 )
458         {
459             const char *name = psz_shortcuts;
460
461             for( unsigned i_short = i_shortcuts; i_short > 0; i_short-- )
462             {
463                 for( unsigned i = 0; i < p_module->i_shortcuts; i++ )
464                 {
465                     char *c;
466                     if( ( c = strchr( name, '@' ) )
467                         ? !strncasecmp( name, p_module->pp_shortcuts[i],
468                                         c-name )
469                         : !strcasecmp( name, p_module->pp_shortcuts[i] ) )
470                     {
471                         /* Found it */
472                         if( c && c[1] )
473                             psz_alias = c+1;
474                         i_shortcut_bonus = i_short * 10000;
475                         goto found_shortcut;
476                     }
477                 }
478
479                 /* Go to the next shortcut... This is so lame! */
480                 name += strlen( name ) + 1;
481             }
482
483             /* If we are in "strict" mode and we couldn't
484              * find the module in the list of provided shortcuts,
485              * then kick the bastard out of here!!! */
486             if( b_strict )
487                 continue;
488         }
489
490         /* Trash <= 0 scored plugins (they can only be selected by shortcut) */
491         if( p_module->i_score <= 0 )
492             continue;
493
494 found_shortcut:
495         /* Store this new module */
496         p_list[count].p_module = p_module;
497         p_list[count].i_score = p_module->i_score + i_shortcut_bonus;
498         p_list[count].b_force = i_shortcut_bonus && b_strict;
499         count++;
500     }
501
502     /* We can release the list, interesting modules are held */
503     module_list_free (p_all);
504
505     /* Sort candidates by descending score */
506     qsort (p_list, count, sizeof (p_list[0]), modulecmp);
507     msg_Dbg( p_this, "looking for %s module: %zu candidate%s", psz_capability,
508              count, count == 1 ? "" : "s" );
509
510     /* Parse the linked list and use the first successful module */
511     va_list args;
512
513     va_start(args, probe);
514     p_module = NULL;
515
516     for (size_t i = 0; (i < count) && (p_module == NULL); i++)
517     {
518         module_t *p_cand = p_list[i].p_module;
519 #ifdef HAVE_DYNAMIC_PLUGINS
520         /* Make sure the module is loaded in mem */
521         module_t *p_real = p_cand->parent ? p_cand->parent : p_cand;
522
523         if (!p_real->b_loaded)
524         {
525             module_t *uncache; /* Map module in process */
526
527             assert (p_real->psz_filename != NULL);
528             uncache = module_InitDynamic (p_this, p_real->psz_filename, false);
529             if (uncache == NULL)
530             {   /* Corrupted module */
531                 msg_Err( p_this, "possibly corrupt module cache" );
532                 continue;
533             }
534             CacheMerge (p_this, p_real, uncache);
535             vlc_module_destroy (uncache);
536         }
537 #endif
538         p_this->b_force = p_list[i].b_force;
539
540         int ret;
541
542         if (likely(p_cand->pf_activate != NULL))
543         {
544             va_list ap;
545
546             va_copy(ap, args);
547             ret = probe(p_cand->pf_activate, ap);
548             va_end(ap);
549         }
550         else
551             ret = VLC_SUCCESS;
552
553         switch (ret)
554         {
555         case VLC_SUCCESS:
556             /* good module! */
557             p_module = p_cand;
558             break;
559
560         case VLC_ETIMEOUT:
561             /* good module, but aborted */
562             break;
563
564         default: /* bad module */
565             continue;
566         }
567     }
568
569     va_end (args);
570     free( p_list );
571     p_this->b_force = b_force_backup;
572
573     if( p_module != NULL )
574     {
575         msg_Dbg( p_this, "using %s module \"%s\"",
576                  psz_capability, module_get_object(p_module) );
577         vlc_object_set_name( p_this, psz_alias ? psz_alias
578                                                : module_get_object(p_module) );
579     }
580     else if( count == 0 )
581         msg_Dbg( p_this, "no %s module matched \"%s\"",
582                  psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
583     else
584         msg_Dbg( p_this, "no %s module matching \"%s\" could be loaded",
585                   psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
586
587     free( psz_shortcuts );
588     free( psz_var );
589
590     stats_TimerStop( p_this, STATS_TIMER_MODULE_NEED );
591     stats_TimerDump( p_this, STATS_TIMER_MODULE_NEED );
592     stats_TimerClean( p_this, STATS_TIMER_MODULE_NEED );
593
594     /* Don't forget that the module is still locked */
595     return p_module;
596 }
597
598
599 /**
600  * Deinstantiates a module.
601  * \param module the module pointer as returned by vlc_module_load()
602  * \param deinit deactivation callback
603  */
604 void vlc_module_unload(module_t *module, vlc_deactivate_t deinit, ...)
605 {
606     if (module->pf_deactivate != NULL)
607     {
608         va_list ap;
609
610         va_start(ap, deinit);
611         deinit(module->pf_deactivate, ap);
612         va_end(ap);
613     }
614 }
615
616
617 static int generic_start(void *func, va_list ap)
618 {
619     vlc_object_t *obj = va_arg(ap, vlc_object_t *);
620     int (*activate)(vlc_object_t *) = func;
621
622     return activate(obj);
623 }
624
625 static void generic_stop(void *func, va_list ap)
626 {
627     vlc_object_t *obj = va_arg(ap, vlc_object_t *);
628     void (*deactivate)(vlc_object_t *) = func;
629
630     deactivate(obj);
631 }
632
633 #undef module_need
634 module_t *module_need(vlc_object_t *obj, const char *cap, const char *name,
635                       bool strict)
636 {
637     return vlc_module_load(obj, cap, name, strict, generic_start, obj);
638 }
639
640 #undef module_unneed
641 void module_unneed(vlc_object_t *obj, module_t *module)
642 {
643     msg_Dbg(obj, "removing module \"%s\"", module_get_object(module));
644     vlc_module_unload(module, generic_stop, obj);
645 }
646
647 /**
648  * Get a pointer to a module_t given it's name.
649  *
650  * \param name the name of the module
651  * \return a pointer to the module or NULL in case of a failure
652  */
653 module_t *module_find (const char *name)
654 {
655     module_t **list, *module;
656
657     assert (name != NULL);
658     list = module_list_get (NULL);
659     if (!list)
660         return NULL;
661
662     for (size_t i = 0; (module = list[i]) != NULL; i++)
663     {
664         if (unlikely(module->i_shortcuts == 0))
665             continue;
666         if (!strcmp (module->pp_shortcuts[0], name))
667             break;
668     }
669     module_list_free (list);
670     return module;
671 }
672
673 /**
674  * Tell if a module exists and release it in thic case
675  *
676  * \param psz_name th name of the module
677  * \return TRUE if the module exists
678  */
679 bool module_exists (const char * psz_name)
680 {
681     return module_find (psz_name) != NULL;
682 }
683
684 /**
685  * Get a pointer to a module_t that matches a shortcut.
686  * This is a temporary hack for SD. Do not re-use (generally multiple modules
687  * can have the same shortcut, so this is *broken* - use module_need()!).
688  *
689  * \param psz_shortcut shortcut of the module
690  * \param psz_cap capability of the module
691  * \return a pointer to the module or NULL in case of a failure
692  */
693 module_t *module_find_by_shortcut (const char *psz_shortcut)
694 {
695     module_t **list, *module;
696
697     list = module_list_get (NULL);
698     if (!list)
699         return NULL;
700
701     for (size_t i = 0; (module = list[i]) != NULL; i++)
702         for (size_t j = 0; j < module->i_shortcuts; j++)
703             if (!strcmp (module->pp_shortcuts[j], psz_shortcut))
704                 goto out;
705 out:
706     module_list_free (list);
707     return module;
708 }
709
710 /**
711  * Get the configuration of a module
712  *
713  * \param module the module
714  * \param psize the size of the configuration returned
715  * \return the configuration as an array
716  */
717 module_config_t *module_config_get( const module_t *module, unsigned *restrict psize )
718 {
719     unsigned i,j;
720     unsigned size = module->confsize;
721     module_config_t *config = malloc( size * sizeof( *config ) );
722
723     assert( psize != NULL );
724     *psize = 0;
725
726     if( !config )
727         return NULL;
728
729     for( i = 0, j = 0; i < size; i++ )
730     {
731         const module_config_t *item = module->p_config + i;
732         if( item->b_internal /* internal option */
733          || item->b_removed /* removed option */ )
734             continue;
735
736         memcpy( config + j, item, sizeof( *config ) );
737         j++;
738     }
739     *psize = j;
740
741     return config;
742 }
743
744 /**
745  * Release the configuration
746  *
747  * \param the configuration
748  * \return nothing
749  */
750 void module_config_free( module_config_t *config )
751 {
752     free( config );
753 }
754
755 /*****************************************************************************
756  * Following functions are local.
757  *****************************************************************************/
758
759 char *psz_vlcpath = NULL;
760
761 #ifdef HAVE_DYNAMIC_PLUGINS
762
763 /*****************************************************************************
764  * AllocateAllPlugins: load all plugin modules we can find.
765  *****************************************************************************/
766 static void AllocateAllPlugins (vlc_object_t *p_this)
767 {
768     const char *vlcpath = psz_vlcpath;
769     char *paths;
770     cache_mode_t mode;
771
772     if( !var_InheritBool( p_this, "plugins-cache" ) )
773         mode = CACHE_IGNORE;
774     else if( var_InheritBool( p_this, "reset-plugins-cache" ) )
775         mode = CACHE_RESET;
776     else
777         mode = CACHE_USE;
778
779     /* Contruct the special search path for system that have a relocatable
780      * executable. Set it to <vlc path>/plugins. */
781     assert( vlcpath );
782
783     if( asprintf( &paths, "%s" DIR_SEP "plugins", vlcpath ) != -1 )
784     {
785         AllocatePluginPath (p_this, paths, mode);
786         free( paths );
787     }
788
789     /* If the user provided a plugin path, we add it to the list */
790     paths = getenv( "VLC_PLUGIN_PATH" );
791     if( paths == NULL )
792         return;
793
794     paths = strdup( paths ); /* don't harm the environment ! :) */
795     if( unlikely(paths == NULL) )
796         return;
797
798     for( char *buf, *path = strtok_r( paths, PATH_SEP, &buf );
799          path != NULL;
800          path = strtok_r( NULL, PATH_SEP, &buf ) )
801         AllocatePluginPath (p_this, path, mode);
802
803     free( paths );
804 }
805
806 struct module_bank
807 {
808     /* Plugins cache */
809     size_t         i_cache;
810     module_cache_t *cache;
811
812     int            i_loaded_cache;
813     module_cache_t *loaded_cache;
814 };
815
816 static void AllocatePluginPath (vlc_object_t *p_this, const char *path,
817                                 cache_mode_t mode)
818 {
819     module_bank_t bank;
820     module_cache_t *cache = NULL;
821     size_t count = 0;
822
823     switch( mode )
824     {
825         case CACHE_USE:
826             count = CacheLoad( p_this, path, &cache );
827             break;
828         case CACHE_RESET:
829             CacheDelete( p_this, path );
830             break;
831         case CACHE_IGNORE:
832             msg_Dbg( p_this, "ignoring plugins cache file" );
833     }
834
835     msg_Dbg( p_this, "recursively browsing `%s'", path );
836
837     bank.cache = NULL;
838     bank.i_cache = 0;
839     bank.loaded_cache = cache;
840     bank.i_loaded_cache = count;
841
842     /* Don't go deeper than 5 subdirectories */
843     AllocatePluginDir (p_this, &bank, path, 5, mode);
844
845     switch( mode )
846     {
847         case CACHE_USE:
848             /* Discard unmatched cache entries */
849             for( size_t i = 0; i < count; i++ )
850             {
851                 if (cache[i].p_module != NULL)
852                    vlc_module_destroy (cache[i].p_module);
853                 free (cache[i].path);
854             }
855             free( cache );
856         case CACHE_RESET:
857             CacheSave (p_this, path, bank.cache, bank.i_cache);
858         case CACHE_IGNORE:
859             break;
860     }
861 }
862
863 /*****************************************************************************
864  * AllocatePluginDir: recursively parse a directory to look for plugins
865  *****************************************************************************/
866 static void AllocatePluginDir( vlc_object_t *p_this, module_bank_t *p_bank,
867                                const char *psz_dir, unsigned i_maxdepth,
868                                cache_mode_t mode )
869 {
870     if( i_maxdepth == 0 )
871         return;
872
873     DIR *dh = vlc_opendir (psz_dir);
874     if (dh == NULL)
875         return;
876
877     /* Parse the directory and try to load all files it contains. */
878     for (;;)
879     {
880         char *file = vlc_readdir (dh), *path;
881         struct stat st;
882
883         if (file == NULL)
884             break;
885
886         /* Skip ".", ".." */
887         if (!strcmp (file, ".") || !strcmp (file, ".."))
888         {
889             free (file);
890             continue;
891         }
892
893         const int pathlen = asprintf (&path, "%s"DIR_SEP"%s", psz_dir, file);
894         free (file);
895         if (pathlen == -1 || vlc_stat (path, &st))
896             continue;
897
898         if (S_ISDIR (st.st_mode))
899             /* Recurse into another directory */
900             AllocatePluginDir (p_this, p_bank, path, i_maxdepth - 1, mode);
901         else
902         if (S_ISREG (st.st_mode)
903          && strncmp (path, "lib", 3)
904          && ((size_t)pathlen >= sizeof ("_plugin"LIBEXT))
905          && !strncasecmp (path + pathlen - strlen ("_plugin"LIBEXT),
906                           "_plugin"LIBEXT, strlen ("_plugni"LIBEXT)))
907             /* ^^ We only load files matching "lib*_plugin"LIBEXT */
908             AllocatePluginFile (p_this, p_bank, path, &st, mode);
909
910         free (path);
911     }
912     closedir (dh);
913 }
914
915 /*****************************************************************************
916  * AllocatePluginFile: load a module into memory and initialize it.
917  *****************************************************************************
918  * This function loads a dynamically loadable module and allocates a structure
919  * for its information data. The module can then be handled by module_need
920  * and module_unneed.
921  *****************************************************************************/
922 static int AllocatePluginFile( vlc_object_t * p_this, module_bank_t *p_bank,
923                                const char *path, const struct stat *st,
924                                cache_mode_t mode )
925 {
926     module_t * p_module = NULL;
927
928     /* Check our plugins cache first then load plugin if needed */
929     if( mode == CACHE_USE )
930         p_module = CacheFind (p_bank->loaded_cache, p_bank->i_loaded_cache,
931                               path, st);
932     if( p_module == NULL )
933         p_module = module_InitDynamic (p_this, path, true);
934     if( p_module == NULL )
935         return -1;
936
937     /* We have not already scanned and inserted this module */
938     assert( p_module->next == NULL );
939
940     /* Unload plugin until we really need it */
941     if( p_module->b_loaded && p_module->b_unloadable )
942     {
943         module_Unload( p_module->handle );
944         p_module->b_loaded = false;
945     }
946
947     /* For now we force loading if the module's config contains
948      * callbacks or actions.
949      * Could be optimized by adding an API call.*/
950     for( size_t n = p_module->confsize, i = 0; i < n; i++ )
951          if( p_module->p_config[i].i_action )
952          {
953              /* !unloadable not allowed for plugins with callbacks */
954              vlc_module_destroy (p_module);
955              p_module = module_InitDynamic (p_this, path, false);
956              break;
957          }
958
959     p_module->next = modules.head;
960     modules.head = p_module;
961
962     if( mode == CACHE_IGNORE )
963         return 0;
964
965     /* Add entry to cache */
966     CacheAdd (&p_bank->cache, &p_bank->i_cache, path, st, p_module);
967     /* TODO: deal with errors */
968     return  0;
969 }
970
971 /**
972  * Loads a dynamically-linked plug-in into memory and initialize it.
973  *
974  * The module can then be handled by module_need() and module_unneed().
975  *
976  * \param path file path of the shared object
977  * \param fast whether to optimize loading for speed or safety
978  *             (fast is used when the plug-in is registered but not used)
979  */
980 static module_t *module_InitDynamic (vlc_object_t *obj,
981                                      const char *path, bool fast)
982 {
983     module_handle_t handle;
984
985     if (module_Load (obj, path, &handle, fast))
986         return NULL;
987
988     /* Try to resolve the symbol */
989     static const char entry_name[] = "vlc_entry" MODULE_SUFFIX;
990     vlc_plugin_cb entry =
991         (vlc_plugin_cb) module_Lookup (handle, entry_name);
992     if (entry == NULL)
993     {
994         msg_Warn (obj, "cannot find plug-in entry point in %s", path);
995         goto error;
996     }
997
998     /* We can now try to call the symbol */
999     module_t *module = entry ();
1000     if (unlikely(module == NULL))
1001     {
1002         /* With a well-written module we shouldn't have to print an
1003          * additional error message here, but just make sure. */
1004         msg_Err (obj, "cannot initialize plug-in %s", path);
1005         goto error;
1006     }
1007
1008     module->psz_filename = strdup (path);
1009     if (unlikely(module->psz_filename == NULL))
1010     {
1011         vlc_module_destroy (module);
1012         goto error;
1013     }
1014     module->handle = handle;
1015     module->b_loaded = true;
1016     return module;
1017 error:
1018     module_Unload( handle );
1019     return NULL;
1020 }
1021 #endif /* HAVE_DYNAMIC_PLUGINS */
1022
1023 /**
1024  * Registers a statically-linked plug-in.
1025  */
1026 static module_t *module_InitStatic (vlc_plugin_cb entry)
1027 {
1028     /* Initializes the module */
1029     module_t *module = entry ();
1030     if (unlikely (module == NULL))
1031         abort (); /* FIXME: OOM or bug */
1032
1033     module->b_loaded = true;
1034     module->b_unloadable = false;
1035
1036     /* LOCK */
1037     module->next = modules.head;
1038     modules.head = module;
1039     /* UNLOCK */
1040
1041     return module;
1042 }