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