1 /*
2 * Copyright (C) 2001 Alan Robertson <alanr@unix.sh>
3 * This software licensed under the GNU LGPL.
4 *
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21 #include <lha_internal.h>
22 #include <unistd.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <sys/stat.h>
30
31 /* Dumbness... */
32 #define time FooTimeParameter
33 #define index FooIndexParameter
34 # include <glib.h>
35 #undef time
36 #undef index
37
38
39 #define ENABLE_PIL_DEFS_PRIVATE
40 #define ENABLE_PLUGIN_MANAGER_PRIVATE
41
42 #ifndef STRLEN_CONST
43 # define STRLEN_CONST(con) (sizeof(con)-1)
44 #endif
45
46 #include <pils/interface.h>
47
48 #define NEW(type) (g_new(type,1))
49 #define ZAP(obj) memset(obj, 0, sizeof(*obj))
50 #define DELETE(obj) {g_free(obj); obj = NULL;}
51
52 #ifdef LTDL_SHLIB_EXT
53 # define PLUGINSUFFIX LTDL_SHLIB_EXT
54 #else
55 # define PLUGINSUFFIX ".so"
56 #endif
57
58 static int PluginDebugLevel = 0;
59
60 #define DEBUGPLUGIN (PluginDebugLevel > 0)
61
62
63
64 static PIL_rc InterfaceManager_plugin_init(PILPluginUniv* univ);
65
66 static char** PILPluginTypeListPlugins(PILPluginType* pitype, int* picount);
67 static PILInterface* FindIF(PILPluginUniv* universe, const char *iftype
68 , const char * ifname);
69 static PIL_rc PluginExists(const char * PluginPath);
70 static char * PILPluginPath(PILPluginUniv* universe, const char * plugintype
71 , const char * pluginname);
72
73
74 void DelPILPluginUniv(PILPluginUniv*);
75 /*
76 * These RmA* functions primarily called from hash_table_foreach,
77 * functions, so they have gpointer arguments. When calling
78 * them by hand, take special care to pass the right argument types.
79 *
80 * They all follow the same calling sequence though. It is:
81 * String name"*" type object
82 * "*" type object with the name given by 1st argument
83 * NULL
84 *
85 * For example:
86 * RmAPILPluginType takes
87 * string name
88 * PILPluginType* object with the given name.
89 */
90 static gboolean RmAPILPluginType
91 ( gpointer pitname /* Name of this plugin type */
92 , gpointer pitype /* PILPluginType* */
93 , gpointer notused
94 );
95 static void RemoveAPILPluginType(PILPluginType*);
96
97 static PILPluginType* NewPILPluginType
98 ( PILPluginUniv* pluginuniv
99 , const char * plugintype
100 );
101 static void DelPILPluginType(PILPluginType*);
102 /*
103 * These RmA* functions primarily called from hash_table_foreach,
104 * so they have gpointer arguments. When calling
105 * them by hand, take special care to pass the right argument types.
106 */
107 static gboolean RmAPILPlugin
108 ( gpointer piname /* Name of this plugin */
109 , gpointer plugin /* PILPlugin* */
110 , gpointer notused
111 );
112 static void RemoveAPILPlugin(PILPlugin*);
113
114
115 static PILPlugin* NewPILPlugin(PILPluginType* pitype
116 , const char * plugin_name
117 , lt_dlhandle dlhand
118 , PILPluginInitFun PluginSym);
119 static void DelPILPlugin(PILPlugin*);
120
121 struct MemStat {
122 unsigned long news;
123 unsigned long frees;
124 };
125
126 static struct PluginStats {
127 struct MemStat plugin;
128 struct MemStat pitype;
129 struct MemStat piuniv;
130 struct MemStat interface;
131 struct MemStat interfacetype;
132 struct MemStat interfaceuniv;
133 }PILstats;
134
135 #define STATNEW(t) {PILstats.t.news ++; }
136 #define STATFREE(t) {PILstats.t.frees ++; }
137
138
139
140 static PILInterfaceUniv* NewPILInterfaceUniv(PILPluginUniv*);
141 static void DelPILInterfaceUniv(PILInterfaceUniv*);
142 /*
143 * These RmA* functions primarily called from hash_table_foreach, but
144 * not necessarily, so they have gpointer arguments. When calling
145 * them by hand, take special care to pass the right argument types.
146 */
147 static gboolean RmAPILInterfaceType
148 ( gpointer iftypename /* Name of this interface type */
149 , gpointer iftype /* PILInterfaceType* */
150 , gpointer notused
151 );
152 static void RemoveAPILInterfaceType(PILInterfaceType*, PILInterfaceType*);
153
154 static PILInterfaceType* NewPILInterfaceType
155 ( PILInterfaceUniv*
156 , const char * typename
157 , void* ifexports, void* user_data
158 );
159 static void DelPILInterfaceType(PILInterfaceType*);
160 /*
161 * These RmA* functions are designed to be called from
162 * hash_table_foreach, so they have gpointer arguments. When calling
163 * them by hand, take special care to pass the right argument types.
164 * They can be called from other places safely also.
165 */
166 static gboolean RmAPILInterface
167 ( gpointer ifname /* Name of this interface */
168 , gpointer plugin /* PILInterface* */
169 , gpointer notused
170 );
171 static PIL_rc RemoveAPILInterface(PILInterface*);
172 static void DelPILPluginType(PILPluginType*);
173
174 static PILInterface* NewPILInterface
175 ( PILInterfaceType* interfacetype
176 , const char* interfacename
177 , void * exports
178 , PILInterfaceFun closefun
179 , void* ud_interface
180 , PILPlugin* loading_plugin /* The plugin that loaded us */
181 );
182 static void DelPILInterface(PILInterface*);
183 static PIL_rc close_ifmgr_interface(PILInterface*, void*);
184
185
186
187
188 /*
189 * For consistency, we show up as a plugin in our our system.
190 *
191 * Here are our exports as a plugin.
192 *
193 */
194 static const char * PIL_PILPluginVersion(void);
195 static void PIL_PILPluginClose (PILPlugin*);
196 void PILpisysSetDebugLevel (int level);
197 int PILpisysGetDebugLevel(void);
198 static const char * PIL_PILPluginLicense (void);
199 static const char * PIL_PILPluginLicenseUrl (void);
200
201 static const PILPluginOps PluginExports =
202 { PIL_PILPluginVersion
203 , PILpisysGetDebugLevel
204 , PILpisysSetDebugLevel
205 , PIL_PILPluginLicense
206 , PIL_PILPluginLicenseUrl
207 , PIL_PILPluginClose
208 };
209
210 /* Prototypes for the functions that we export to every plugin */
211 static PIL_rc PILregister_plugin(PILPlugin* piinfo, const PILPluginOps* mops);
212 static PIL_rc PILunregister_plugin(PILPlugin* piinfo);
213 static PIL_rc
214 PILRegisterInterface
215 ( PILPlugin* piinfo
216 , const char * interfacetype /* Type of interface */
217 , const char * interfacename /* Name of interface */
218 , void* Ops /* Ops exported by this interface */
219 , PILInterfaceFun closefunc /* Ops exported by this interface */
220 , PILInterface** interfaceid /* Interface id (OP) */
221 , void** Imports /* Functions imported by */
222 /* this interface (OP) */
223 , void* ud_interface /* interface user data */
224 );
225 static PIL_rc PILunregister_interface(PILInterface* interfaceid);
226 static void PILLog(PILLogLevel priority, const char * fmt, ...)
227 G_GNUC_PRINTF(2,3);
228
229
230 /*
231 * This is the set of functions that we export to every plugin
232 *
233 * That also makes it the set of functions that every plugin imports.
234 *
235 */
236
237 static PILPluginImports PILPluginImportSet =
238 { PILregister_plugin /* register_plugin */
239 , PILunregister_plugin /* unregister_plugin */
240 , PILRegisterInterface /* register_interface */
241 , RemoveAPILInterface /* unregister_interface */
242 , PILLoadPlugin /* load_plugin */
243 , PILLog /* Logging function */
244 , g_malloc /* Malloc function */
245 , g_realloc /* realloc function */
246 , g_free /* Free function */
247 , g_strdup /* Strdup function */
248 };
249
250 static PIL_rc ifmgr_register_interface(PILInterface* newif
251 , void** imports);
252 static PIL_rc ifmgr_unregister_interface(PILInterface* interface);
253
254 /*
255 * For consistency, the master interface manager is a interface in the
256 * system. Below is our set of exported Interface functions.
257 *
258 * Food for thought: This is the interface manager whose name is
259 * interface. This makes it the Interface Interface interface ;-)
260 * (or the Interface/Interface interface if you prefer)
261 */
262
263 static PILInterfaceOps IfExports =
264 { ifmgr_register_interface
265 , ifmgr_unregister_interface
266 };
267
268
269
270 /*
271 * Below is the set of functions we export to every interface manager.
272 */
273
274 static int IfRefCount(PILInterface * ifh);
275 static int IfIncrRefCount(PILInterface*eifinfo,int plusminus);
276 static int PluginIncrRefCount(PILPlugin*eifinfo,int plusminus);
277 #if 0
278 static int PluginRefCount(PILPlugin * ifh);
279 #endif
280 static void IfForceUnregister(PILInterface *eifinfo);
281 static void IfForEachClientRemove(PILInterface* manangerif
282 , gboolean(*f)(PILInterface* clientif, void * other)
283 , void* other);
284
285 static PILInterfaceImports IFManagerImports =
286 { IfRefCount
287 , IfIncrRefCount
288 , IfForceUnregister
289 , IfForEachClientRemove
290 };
291 static void PILValidatePlugin(gpointer key, gpointer plugin, gpointer pitype);
292 static void PILValidatePluginType(gpointer key, gpointer pitype, gpointer piuniv);
293 static void PILValidatePluginUniv(gpointer key, gpointer pitype, gpointer);
294 static void PILValidateInterface(gpointer key, gpointer interface, gpointer iftype);
295 static void PILValidateInterfaceType(gpointer key, gpointer iftype, gpointer ifuniv);
296 static void PILValidateInterfaceUniv(gpointer key, gpointer puniv, gpointer);
297
298 /*****************************************************************************
299 *
300 * This code is for managing plugins, and interacting with them...
301 *
302 ****************************************************************************/
303
304 static PILPlugin*
NewPILPlugin(PILPluginType * pitype,const char * plugin_name,lt_dlhandle dlhand,PILPluginInitFun PluginSym)305 NewPILPlugin( PILPluginType* pitype
306 , const char * plugin_name
307 , lt_dlhandle dlhand
308 , PILPluginInitFun PluginSym)
309 {
310 PILPlugin* ret = NEW(PILPlugin);
311
312 if (DEBUGPLUGIN) {
313 PILLog(PIL_DEBUG, "NewPILPlugin(0x%lx)", (unsigned long)ret);
314 }
315
316 STATNEW(plugin);
317 ret->MagicNum = PIL_MAGIC_PLUGIN;
318 ret->plugin_name = g_strdup(plugin_name);
319 ret->plugintype = pitype;
320 ret->refcnt = 0;
321 ret->dlhandle = dlhand;
322 ret->dlinitfun = PluginSym;
323 PILValidatePlugin(ret->plugin_name, ret, pitype);
324 return ret;
325 }
326 static void
DelPILPlugin(PILPlugin * pi)327 DelPILPlugin(PILPlugin*pi)
328 {
329
330 if (pi->refcnt > 0) {
331 PILLog(PIL_INFO, "DelPILPlugin: Non-zero refcnt");
332 }
333
334 if (pi->dlhandle) {
335 if (DEBUGPLUGIN) {
336 PILLog(PIL_DEBUG, "Closing dlhandle for (%s/%s)"
337 , pi->plugintype->plugintype, pi->plugin_name);
338 }
339 lt_dlclose(pi->dlhandle);
340 }else if (DEBUGPLUGIN) {
341 PILLog(PIL_DEBUG, "NO dlhandle for (%s/%s)!"
342 , pi->plugintype->plugintype, pi->plugin_name);
343 }
344 DELETE(pi->plugin_name);
345 ZAP(pi);
346 DELETE(pi);
347 STATFREE(plugin);
348 }
349
350
351 static PILPluginType dummymlpitype =
352 { PIL_MAGIC_PLUGINTYPE
353 , NULL /*plugintype*/
354 , NULL /*piuniv*/
355 , NULL /*Plugins*/
356 , PILPluginTypeListPlugins /* listplugins */
357 };
358
359 static PILPluginType*
NewPILPluginType(PILPluginUniv * pluginuniv,const char * plugintype)360 NewPILPluginType(PILPluginUniv* pluginuniv
361 , const char * plugintype
362 )
363 {
364 PILPluginType* ret = NEW(PILPluginType);
365 if (DEBUGPLUGIN) {
366 PILLog(PIL_DEBUG, "NewPILPlugintype(0x%lx)", (unsigned long)ret);
367 }
368 STATNEW(pitype);
369
370 *ret = dummymlpitype;
371
372 ret->plugintype = g_strdup(plugintype);
373 ret->piuniv = pluginuniv;
374 ret->Plugins = g_hash_table_new(g_str_hash, g_str_equal);
375 g_hash_table_insert(pluginuniv->PluginTypes
376 , g_strdup(ret->plugintype), ret);
377 PILValidatePluginType(ret->plugintype, ret, pluginuniv);
378 return ret;
379 }
380 static void
DelPILPluginType(PILPluginType * pitype)381 DelPILPluginType(PILPluginType*pitype)
382 {
383 PILValidatePluginType(NULL, pitype, NULL);
384 if (DEBUGPLUGIN) {
385 PILLog(PIL_DEBUG, "DelPILPluginType(%s)", pitype->plugintype);
386 }
387
388 STATFREE(pitype);
389 g_hash_table_foreach_remove(pitype->Plugins, RmAPILPlugin, NULL);
390 g_hash_table_destroy(pitype->Plugins);
391 DELETE(pitype->plugintype);
392 ZAP(pitype);
393 DELETE(pitype);
394 }
395 /*
396 * These RmA* functions primarily called from hash_table_foreach,
397 * so they have gpointer arguments. This *not necessarily* clause
398 * is why they do the g_hash_table_lookup_extended call instead of
399 * just deleting the key. When called from outside, the key *
400 * may not be pointing at the key to actually free, but a copy
401 * of the key.
402 */
403 static gboolean
RmAPILPlugin(gpointer piname,gpointer plugin,gpointer notused)404 RmAPILPlugin /* IsA GHFunc: required for g_hash_table_foreach_remove() */
405 ( gpointer piname /* Name of this plugin */
406 , gpointer plugin /* PILPlugin* */
407 , gpointer notused
408 )
409 {
410 PILPlugin* Plugin = plugin;
411 PILPluginType* Pitype = Plugin->plugintype;
412
413 PILValidatePlugin(piname, plugin, NULL);
414 PILValidatePluginType(NULL, Pitype, NULL);
415 g_assert(IS_PILPLUGIN(Plugin));
416
417 if (DEBUGPLUGIN) {
418 PILLog(PIL_DEBUG, "RmAPILPlugin(%s/%s)", Pitype->plugintype
419 , Plugin->plugin_name);
420 }
421 /* Normally called from g_hash_table_foreachremove or equivalent */
422
423 DelPILPlugin(plugin);
424 DELETE(piname);
425 return TRUE;
426 }
427
428 static void
RemoveAPILPlugin(PILPlugin * Plugin)429 RemoveAPILPlugin(PILPlugin*Plugin)
430 {
431 PILPluginType* Pitype = Plugin->plugintype;
432 gpointer key;
433 if (DEBUGPLUGIN) {
434 PILLog(PIL_DEBUG, "RemoveAPILPlugin(%s/%s)"
435 , Pitype->plugintype
436 , Plugin->plugin_name);
437 }
438 if (g_hash_table_lookup_extended(Pitype->Plugins
439 , Plugin->plugin_name, &key, (void*)&Plugin)) {
440
441 g_hash_table_remove(Pitype->Plugins, key);
442 RmAPILPlugin(key, Plugin, NULL);
443 key = NULL;
444 Plugin = NULL;
445
446 }else{
447 g_assert_not_reached();
448 }
449 if (g_hash_table_size(Pitype->Plugins) == 0) {
450 RemoveAPILPluginType(Pitype);
451 /* Pitype is now invalid */
452 Pitype = NULL;
453 }
454 }
455
456 PILPluginUniv*
NewPILPluginUniv(const char * basepluginpath)457 NewPILPluginUniv(const char * basepluginpath)
458 {
459 PILPluginUniv* ret = NEW(PILPluginUniv);
460
461 /* The delimiter separating search path components */
462 const char* path_delim = G_SEARCHPATH_SEPARATOR_S;
463 char * fullpath;
464
465 STATNEW(piuniv);
466 if (DEBUGPLUGIN) {
467 PILLog(PIL_DEBUG, "NewPILPluginUniv(0x%lx)"
468 , (unsigned long)ret);
469 }
470 if (!g_path_is_absolute(basepluginpath)) {
471 DELETE(ret);
472 return(ret);
473 }
474 ret->MagicNum = PIL_MAGIC_PLUGINUNIV;
475 fullpath = g_strdup_printf("%s%s%s", basepluginpath
476 , path_delim, PILS_BASE_PLUGINDIR);
477 if (DEBUGPLUGIN) {
478 PILLog(PIL_DEBUG
479 , "PILS: Plugin path = %s", fullpath);
480 }
481
482 /* Separate the root directory PATH into components */
483 ret->rootdirlist = g_strsplit(fullpath, path_delim, 100);
484 g_free(fullpath);
485
486 ret->PluginTypes = g_hash_table_new(g_str_hash, g_str_equal);
487 ret->imports = &PILPluginImportSet;
488 ret->ifuniv = NewPILInterfaceUniv(ret);
489 PILValidatePluginUniv(NULL, ret, NULL);
490 return ret;
491 }
492
493 /* Change memory allocation functions immediately after creating universe */
494 void
PilPluginUnivSetMemalloc(PILPluginUniv * u,gpointer (* allocfun)(glib_size_t size),gpointer (* reallocfun)(gpointer ptr,glib_size_t size),void (* freefun)(void * space),char * (* strdupfun)(const char * s))495 PilPluginUnivSetMemalloc(PILPluginUniv* u
496 , gpointer (*allocfun)(glib_size_t size)
497 , gpointer (*reallocfun)(gpointer ptr, glib_size_t size)
498 , void (*freefun)(void* space)
499 , char* (*strdupfun)(const char *s))
500 {
501 u->imports->alloc = allocfun;
502 u->imports->mrealloc = reallocfun;
503 u->imports->mfree = freefun;
504 u->imports->mstrdup = strdupfun;
505 }
506
507
508 /* Change logging functions - preferably right after creating universe */
509 void
PilPluginUnivSetLog(PILPluginUniv * u,void (* logfun)(PILLogLevel priority,const char * fmt,...))510 PilPluginUnivSetLog(PILPluginUniv* u
511 , void (*logfun) (PILLogLevel priority, const char * fmt, ...))
512 {
513 u->imports->log = logfun;
514 }
515
516 void
DelPILPluginUniv(PILPluginUniv * piuniv)517 DelPILPluginUniv(PILPluginUniv* piuniv)
518 {
519
520
521 if (DEBUGPLUGIN) {
522 PILLog(PIL_DEBUG, "DelPILPluginUniv(0x%lx)"
523 , (unsigned long)piuniv);
524 }
525 STATFREE(piuniv);
526 PILValidatePluginUniv(NULL, piuniv, NULL);
527 DelPILInterfaceUniv(piuniv->ifuniv);
528 piuniv->ifuniv = NULL;
529 g_hash_table_foreach_remove(piuniv->PluginTypes
530 , RmAPILPluginType, NULL);
531 g_hash_table_destroy(piuniv->PluginTypes);
532 g_strfreev(piuniv->rootdirlist);
533 ZAP(piuniv);
534 DELETE(piuniv);
535 }
536
537 /*
538 * These RmA* functions primarily called from hash_table_foreach,
539 * so they have gpointer arguments. This *not necessarily* clause
540 * is why they do the g_hash_table_lookup_extended call instead of
541 * just deleting the key. When called from outside, the key *
542 * may not be pointing at the key to actually free, but a copy
543 * of the key.
544 */
545 static gboolean /* IsA GHFunc: required for g_hash_table_foreach_remove() */
RmAPILPluginType(gpointer pitname,gpointer pitype,gpointer notused)546 RmAPILPluginType
547 ( gpointer pitname /* Name of this plugin type "real" key */
548 , gpointer pitype /* PILPluginType* */
549 , gpointer notused
550 )
551 {
552 PILPluginType* Plugintype = pitype;
553
554 g_assert(IS_PILPLUGINTYPE(Plugintype));
555 PILValidatePluginType(pitname, pitype, NULL);
556 if (DEBUGPLUGIN) {
557 PILLog(PIL_DEBUG, "RmAPILPluginType(%s)"
558 , Plugintype->plugintype);
559 }
560 /*
561 * This function is usually but not always called by
562 * g_hash_table_foreach_remove()
563 */
564
565 DelPILPluginType(pitype);
566 DELETE(pitname);
567 return TRUE;
568 }
569 static void
RemoveAPILPluginType(PILPluginType * Plugintype)570 RemoveAPILPluginType(PILPluginType*Plugintype)
571 {
572 PILPluginUniv* Pluginuniv = Plugintype->piuniv;
573 gpointer key;
574 if (g_hash_table_lookup_extended(Pluginuniv->PluginTypes
575 , Plugintype->plugintype, &key, (void*)&Plugintype)) {
576
577 g_hash_table_remove(Pluginuniv->PluginTypes, key);
578 RmAPILPluginType(key, Plugintype, NULL);
579 }else{
580 g_assert_not_reached();
581 }
582 }
583
584 /*
585 * InterfaceManager_plugin_init: Initialize the handling of
586 * "Interface Manager" interfaces.
587 *
588 * There are a few potential bootstrapping problems here ;-)
589 *
590 */
591 static PIL_rc
InterfaceManager_plugin_init(PILPluginUniv * univ)592 InterfaceManager_plugin_init(PILPluginUniv* univ)
593 {
594 PILPluginImports* imports = univ->imports;
595 PILPluginType* pitype;
596 PILInterface* ifinfo;
597 PILInterfaceType* iftype;
598 void* dontcare;
599 PILPlugin* ifmgr_plugin;
600 PIL_rc rc;
601
602
603 iftype = NewPILInterfaceType(univ->ifuniv, PI_IFMANAGER, &IfExports
604 , NULL);
605
606 g_hash_table_insert(univ->ifuniv->iftypes
607 , g_strdup(PI_IFMANAGER), iftype);
608
609 pitype = NewPILPluginType(univ, PI_IFMANAGER);
610
611 g_hash_table_insert(univ->PluginTypes
612 , g_strdup(PI_IFMANAGER), pitype);
613
614 ifmgr_plugin= NewPILPlugin(pitype, PI_IFMANAGER, NULL, NULL);
615
616 g_hash_table_insert(pitype->Plugins
617 , g_strdup(PI_IFMANAGER), ifmgr_plugin);
618
619 /* We can call register_plugin, since it doesn't depend on us... */
620 rc = imports->register_plugin(ifmgr_plugin, &PluginExports);
621 if (rc != PIL_OK) {
622 PILLog(PIL_CRIT, "register_plugin() failed in init: %s"
623 , PIL_strerror(rc));
624 return(rc);
625 }
626 /*
627 * Now, we're registering interfaces, and are into some deep
628 * Catch-22 if do it the "easy" way, since our code is
629 * needed in order to support interface loading for the type of
630 * interface we are (a Interface interface).
631 *
632 * So, instead of calling imports->register_interface(), we have to
633 * do the work ourselves here...
634 *
635 * Since no one should yet be registered to handle Interface
636 * interfaces, we need to bypass the hash table handler lookup
637 * that register_interface would do and call the function that
638 * register_interface would call...
639 *
640 */
641
642 /* The first argument is the PILInterfaceType* */
643 ifinfo = NewPILInterface(iftype, PI_IFMANAGER, &IfExports
644 , close_ifmgr_interface, NULL, NULL);
645 ifinfo->ifmanager = iftype->ifmgr_ref = ifinfo;
646 if (DEBUGPLUGIN) {
647 PILLog(PIL_DEBUG, "InterfaceManager_plugin_init(0x%lx/%s)"
648 , (unsigned long)ifinfo, ifinfo->interfacename);
649 }
650 PILValidatePluginUniv(NULL, univ, NULL);
651 ifmgr_register_interface(ifinfo, &dontcare);
652 PILValidatePluginUniv(NULL, univ, NULL);
653
654 return(PIL_OK);
655 }/*InterfaceManager_plugin_init*/
656
657
658 /* Return current IfIf "plugin" version (not very interesting for us) */
659 static const char *
PIL_PILPluginVersion(void)660 PIL_PILPluginVersion(void)
661 {
662 return("1.0");
663 }
664
665 /* Return current IfIf debug level */
666 int
PILpisysGetDebugLevel(void)667 PILpisysGetDebugLevel(void)
668 {
669 return(PluginDebugLevel);
670 }
671
672 /* Set current IfIf debug level */
673 void
PILpisysSetDebugLevel(int level)674 PILpisysSetDebugLevel (int level)
675 {
676 PluginDebugLevel = level;
677 }
678 struct set_debug_helper {
679 const char * pitype;
680 const char * piname;
681 int level;
682 };
683
684 static void
PILSetDebugLeveltoPlugin(gpointer key,gpointer plugin,gpointer Helper)685 PILSetDebugLeveltoPlugin(gpointer key, gpointer plugin, gpointer Helper)
686 {
687 PILPlugin* p = plugin;
688 struct set_debug_helper* helper = Helper;
689
690 p->pluginops->setdebuglevel(helper->level);
691 }
692
693 static void
PILSetDebugLevelbyType(const void * key,gpointer plugintype,gpointer Helper)694 PILSetDebugLevelbyType(const void * key, gpointer plugintype, gpointer Helper)
695 {
696 struct set_debug_helper* helper = Helper;
697
698
699 PILPluginType* t = plugintype;
700
701 if (helper->piname == NULL) {
702 g_hash_table_foreach(t->Plugins, PILSetDebugLeveltoPlugin
703 , helper);
704 }else{
705 PILPlugin* p = g_hash_table_lookup(t->Plugins
706 , helper->piname);
707 if (p != NULL) {
708 p->pluginops->setdebuglevel(helper->level);
709 }
710 }
711 }
712
713 void
PILSetDebugLevel(PILPluginUniv * u,const char * pitype,const char * piname,int level)714 PILSetDebugLevel(PILPluginUniv* u, const char * pitype, const char * piname
715 , int level)
716 {
717 struct set_debug_helper helper = {pitype, piname, level};
718
719 if (u == NULL) {
720 return;
721 }
722
723 if (pitype == NULL) {
724 g_hash_table_foreach(u->PluginTypes
725 /*
726 * Reason for this next cast:
727 * SetDebugLevelbyType takes const gpointer
728 * arguments, unlike a GHFunc which doesn't.
729 */
730 , (GHFunc)PILSetDebugLevelbyType
731 , &helper);
732 }else{
733 PILPluginType* t = g_hash_table_lookup(u->PluginTypes
734 , pitype);
735 if (t != NULL) {
736 PILSetDebugLevelbyType(pitype, t, &helper);
737 }
738 }
739 }
740
741
742 int
PILGetDebugLevel(PILPluginUniv * u,const char * pitype,const char * piname)743 PILGetDebugLevel(PILPluginUniv* u, const char * pitype, const char * piname)
744 {
745 PILPluginType* t;
746 PILPlugin* p;
747 if ( u == NULL
748 || pitype == NULL
749 || (t = g_hash_table_lookup(u->PluginTypes, pitype)) == NULL
750 || (p = g_hash_table_lookup(t->Plugins, piname)) == NULL) {
751 return -1;
752 }
753 return p->pluginops->getdebuglevel();
754 }
755
756 /* Close/shutdown our PILPlugin (the interface manager interface plugin) */
757 /* All our interfaces will have already been shut down and unregistered */
758 static void
PIL_PILPluginClose(PILPlugin * plugin)759 PIL_PILPluginClose (PILPlugin* plugin)
760 {
761 }
762 static const char *
PIL_PILPluginLicense(void)763 PIL_PILPluginLicense (void)
764 {
765 return LICENSE_LGPL;
766 }
767 static const char *
PIL_PILPluginLicenseUrl(void)768 PIL_PILPluginLicenseUrl (void)
769 {
770 return URL_LGPL;
771 }
772
773 /*****************************************************************************
774 *
775 * This code is for managing interfaces, and interacting with them...
776 *
777 ****************************************************************************/
778
779
780 static PILInterface*
NewPILInterface(PILInterfaceType * interfacetype,const char * interfacename,void * exports,PILInterfaceFun closefun,void * ud_interface,PILPlugin * loading_plugin)781 NewPILInterface(PILInterfaceType* interfacetype
782 , const char* interfacename
783 , void * exports
784 , PILInterfaceFun closefun
785 , void* ud_interface
786 , PILPlugin* loading_plugin)
787 {
788 PILInterface* ret = NULL;
789 PILInterface* look = NULL;
790
791
792 if ((look = g_hash_table_lookup(interfacetype->interfaces
793 , interfacename)) != NULL) {
794 PILLog(PIL_DEBUG, "Deleting PILInterface!");
795 DelPILInterface(look);
796 }
797 ret = NEW(PILInterface);
798 STATNEW(interface);
799 if (DEBUGPLUGIN) {
800 PILLog(PIL_DEBUG, "NewPILInterface(0x%lx)", (unsigned long)ret);
801 }
802
803 if (ret) {
804 ret->MagicNum = PIL_MAGIC_INTERFACE;
805 ret->interfacetype = interfacetype;
806 ret->exports = exports;
807 ret->ud_interface = ud_interface;
808 ret->interfacename = g_strdup(interfacename);
809 ret->ifmanager = interfacetype->ifmgr_ref;
810 ret->loadingpi = loading_plugin;
811 g_hash_table_insert(interfacetype->interfaces
812 , g_strdup(ret->interfacename), ret);
813
814 ret->if_close = closefun;
815 ret->refcnt = 1;
816 if (DEBUGPLUGIN) {
817 PILLog(PIL_DEBUG, "NewPILInterface(0x%lx:%s/%s)*** user_data: 0x%p *******"
818 , (unsigned long)ret
819 , interfacetype->typename
820 , ret->interfacename
821 , ud_interface);
822 }
823 }
824 return ret;
825 }
826 static void
DelPILInterface(PILInterface * intf)827 DelPILInterface(PILInterface* intf)
828 {
829 if (DEBUGPLUGIN) {
830 PILLog(PIL_DEBUG, "DelPILInterface(0x%lx/%s)"
831 , (unsigned long)intf, intf->interfacename);
832 }
833 STATFREE(interface);
834 DELETE(intf->interfacename);
835 ZAP(intf);
836 DELETE(intf);
837 }
838
839 static PILInterfaceType*
NewPILInterfaceType(PILInterfaceUniv * univ,const char * typename,void * ifeports,void * user_data)840 NewPILInterfaceType(PILInterfaceUniv*univ, const char * typename
841 , void* ifeports, void* user_data)
842 {
843 PILInterfaceType* ifmgr_types;
844 PILInterface* ifmgr_ref;
845 PILInterfaceType* ret = NEW(PILInterfaceType);
846
847
848 STATNEW(interfacetype);
849 ret->MagicNum = PIL_MAGIC_INTERFACETYPE;
850 ret->typename = g_strdup(typename);
851 ret->interfaces = g_hash_table_new(g_str_hash, g_str_equal);
852 ret->ud_if_type = user_data;
853 ret->universe = univ;
854 ret->ifmgr_ref = NULL;
855
856 /* Now find the pointer to our if type in the Interface Universe */
857 if ((ifmgr_types = g_hash_table_lookup(univ->iftypes, PI_IFMANAGER))
858 != NULL) {
859 if ((ifmgr_ref=g_hash_table_lookup(ifmgr_types->interfaces
860 , typename)) != NULL) {
861 ret->ifmgr_ref = ifmgr_ref;
862 }else {
863 g_assert(strcmp(typename, PI_IFMANAGER) == 0);
864 }
865 }else {
866 g_assert(strcmp(typename, PI_IFMANAGER) == 0);
867 }
868
869 /* Insert ourselves into our parent's table */
870 g_hash_table_insert(univ->iftypes, g_strdup(typename), ret);
871 return ret;
872 }
873 static void
DelPILInterfaceType(PILInterfaceType * ift)874 DelPILInterfaceType(PILInterfaceType*ift)
875 {
876 PILInterfaceUniv* u = ift->universe;
877 if (DEBUGPLUGIN) {
878 PILLog(PIL_DEBUG, "DelPILInterfaceType(%s)"
879 , ift->typename);
880 }
881 STATFREE(interfacetype);
882
883 PILValidateInterfaceUniv(NULL, u, NULL);
884
885 /*
886 * RmAPILInterface refuses to remove the interface for the
887 * Interface manager, because it must be removed last.
888 *
889 * Otherwise we won't be able to unregister interfaces
890 * for other types of objects, and we'll be very confused.
891 */
892
893 g_hash_table_foreach_remove(ift->interfaces, RmAPILInterface, NULL);
894
895 PILValidateInterfaceUniv(NULL, u, NULL);
896
897 if (g_hash_table_size(ift->interfaces) > 0) {
898 gpointer key, iftype;
899 if (DEBUGPLUGIN) {
900 PILLog(PIL_DEBUG
901 , "DelPILInterfaceType(%s): table size (%d)"
902 , ift->typename, g_hash_table_size(ift->interfaces));
903 }
904 if (g_hash_table_lookup_extended(ift->interfaces
905 , PI_IFMANAGER, &key, &iftype)) {
906 DelPILInterface((PILInterface*)iftype);
907 DELETE(key);
908 }
909 }
910 DELETE(ift->typename);
911 g_hash_table_destroy(ift->interfaces);
912 ZAP(ift);
913 DELETE(ift);
914 }
915
916 /*
917 * These RmA* functions primarily called from hash_table_foreach,
918 * so they have gpointer arguments. This *not necessarily* clause
919 * is why they do the g_hash_table_lookup_extended call instead of
920 * just deleting the key. When called from outside, the key *
921 * may not be pointing at the key to actually free, but a copy
922 * of the key.
923 */
924 static gboolean /* IsAGHFunc: required for g_hash_table_foreach_remove() */
RmAPILInterface(gpointer ifname,gpointer intf,gpointer notused)925 RmAPILInterface
926 ( gpointer ifname /* Name of this interface */
927 , gpointer intf /* PILInterface* */
928 , gpointer notused
929 )
930 {
931 PILInterface* If = intf;
932 PILInterfaceType* Iftype = If->interfacetype;
933
934 if (DEBUGPLUGIN) {
935 PILLog(PIL_DEBUG, "RmAPILInterface(0x%lx/%s)"
936 , (unsigned long)If, If->interfacename);
937 }
938 g_assert(IS_PILINTERFACE(If));
939
940 /*
941 * Don't remove the master interface manager this way, or
942 * Somebody will have a cow...
943 */
944 if (If == If->ifmanager) {
945 if (DEBUGPLUGIN) {
946 PILLog(PIL_DEBUG, "RmAPILInterface: skipping (%s)"
947 , If->interfacename);
948 }
949 return FALSE;
950 }
951 PILValidateInterface(ifname, If, Iftype);
952 PILValidateInterfaceType(NULL, Iftype, NULL);
953
954 /*
955 * This function is usually but not always called by
956 * g_hash_table_foreach_remove()
957 */
958
959 PILunregister_interface(If);
960 PILValidateInterface(ifname, If, Iftype);
961 PILValidateInterfaceType(NULL, Iftype, NULL);
962 DELETE(ifname);
963 DelPILInterface(If);
964 return TRUE;
965 }
966 static PIL_rc
RemoveAPILInterface(PILInterface * pif)967 RemoveAPILInterface(PILInterface* pif)
968 {
969 PILInterfaceType* Iftype = pif->interfacetype;
970 gpointer key;
971
972 if (DEBUGPLUGIN) {
973 PILLog(PIL_DEBUG, "RemoveAPILInterface(0x%lx/%s)"
974 , (unsigned long)pif, pif->interfacename);
975 }
976 if (g_hash_table_lookup_extended(Iftype->interfaces
977 , pif->interfacename, &key, (void*)&pif)) {
978 g_assert(IS_PILINTERFACE(pif));
979 g_hash_table_remove(Iftype->interfaces, key);
980 RmAPILInterface(key, pif, NULL);
981 }else{
982 g_assert_not_reached();
983 }
984
985 if (g_hash_table_size(Iftype->interfaces) == 0) {
986 /* The generic plugin handler doesn't want us to
987 * delete it's types...
988 */
989 if (Iftype->ifmgr_ref->refcnt <= 1) {
990 RemoveAPILInterfaceType(Iftype, NULL);
991 }
992 }
993 return PIL_OK;
994 }
995
996
997 /* Register a Interface Interface (Interface manager) */
998 static PIL_rc
ifmgr_register_interface(PILInterface * intf,void ** imports)999 ifmgr_register_interface(PILInterface* intf
1000 , void** imports)
1001 {
1002 PILInterfaceType* ift = intf->interfacetype;
1003 PILInterfaceUniv* ifuniv = ift->universe;
1004 PILInterfaceOps* ifops; /* Ops vector for InterfaceManager */
1005
1006 if (DEBUGPLUGIN) {
1007 PILLog(PIL_DEBUG
1008 , "Registering Implementation manager for"
1009 " Interface type '%s'"
1010 , intf->interfacename);
1011 }
1012
1013 ifops = intf->exports;
1014 if (ifops->RegisterInterface == NULL
1015 || ifops->UnRegisterInterface == NULL) {
1016 PILLog(PIL_DEBUG, "ifmgr_register_interface(%s)"
1017 ": NULL exported function pointer"
1018 , intf->interfacename);
1019 return PIL_INVAL;
1020 }
1021
1022 *imports = &IFManagerImports;
1023
1024 if(g_hash_table_lookup(ifuniv->iftypes, intf->interfacename) == NULL){
1025 /* It registers itself into ifuniv automatically */
1026 NewPILInterfaceType(ifuniv,intf->interfacename, &IfExports
1027 , NULL);
1028 }
1029 return PIL_OK;
1030 }
1031
1032 static gboolean
RemoveAllClients(PILInterface * interface,void * managerif)1033 RemoveAllClients(PILInterface*interface, void * managerif)
1034 {
1035 /*
1036 * Careful! We can't remove ourselves this way...
1037 * This gets taken care of as a special case in DelPILInterfaceUniv...
1038 */
1039 if (managerif == interface) {
1040 return FALSE;
1041 }
1042 PILunregister_interface(interface);
1043 return TRUE;
1044 }
1045
1046 /* Unconditionally unregister a interface manager (InterfaceMgr Interface) */
1047 static PIL_rc
ifmgr_unregister_interface(PILInterface * interface)1048 ifmgr_unregister_interface(PILInterface* interface)
1049 {
1050 /*
1051 * We need to unregister every interface we manage
1052 */
1053 if (DEBUGPLUGIN) {
1054 PILLog(PIL_DEBUG, "ifmgr_unregister_interface(%s)"
1055 , interface->interfacename);
1056 }
1057
1058 IfForEachClientRemove(interface, RemoveAllClients, interface);
1059 return PIL_OK;
1060 }
1061
1062 /* Called to close the Interface manager for type Interface */
1063 static PIL_rc
close_ifmgr_interface(PILInterface * us,void * ud_interface)1064 close_ifmgr_interface(PILInterface* us, void* ud_interface)
1065 {
1066 if (DEBUGPLUGIN) {
1067 PILLog(PIL_DEBUG, "close_ifmgr_interface(%s)"
1068 , us->interfacename);
1069 }
1070 /* Nothing much to do */
1071 return PIL_OK;
1072 }
1073
1074 /* Return the reference count for this interface */
1075 static int
IfRefCount(PILInterface * eifinfo)1076 IfRefCount(PILInterface * eifinfo)
1077 {
1078 return eifinfo->refcnt;
1079 }
1080
1081 /* Modify the reference count for this interface */
1082 static int
IfIncrRefCount(PILInterface * eifinfo,int plusminus)1083 IfIncrRefCount(PILInterface*eifinfo, int plusminus)
1084 {
1085 if(DEBUGPLUGIN) {
1086 PILLog(PIL_DEBUG, "IfIncrRefCount(%d + %d )"
1087 , eifinfo->refcnt, plusminus);
1088 }
1089 eifinfo->refcnt += plusminus;
1090 if (eifinfo->refcnt <= 0) {
1091 eifinfo->refcnt = 0;
1092 /* Unregister this interface. */
1093 RemoveAPILInterface(eifinfo);
1094 return 0;
1095 }
1096 return eifinfo->refcnt;
1097 }
1098
1099 #if 0
1100 static int
1101 PluginRefCount(PILPlugin * pi)
1102 {
1103 return pi->refcnt;
1104 }
1105 #endif
1106
1107 static int
PluginIncrRefCount(PILPlugin * pi,int plusminus)1108 PluginIncrRefCount(PILPlugin*pi, int plusminus)
1109 {
1110 if (DEBUGPLUGIN) {
1111 PILLog(PIL_DEBUG, "PluginIncrRefCount(%d + %d )"
1112 , pi->refcnt, plusminus);
1113 }
1114 pi->refcnt += plusminus;
1115 if (pi->refcnt <= 0) {
1116 pi->refcnt = 0;
1117 RemoveAPILPlugin(pi);
1118 return 0;
1119 }
1120 return pi->refcnt;
1121 }
1122
1123 static PILInterface*
FindIF(PILPluginUniv * universe,const char * iftype,const char * ifname)1124 FindIF(PILPluginUniv* universe, const char *iftype, const char * ifname)
1125 {
1126 PILInterfaceUniv* puniv;
1127 PILInterfaceType* ptype;
1128
1129 if (universe == NULL || (puniv = universe->ifuniv) == NULL
1130 || (ptype=g_hash_table_lookup(puniv->iftypes, iftype))==NULL){
1131 return NULL;
1132 }
1133 return g_hash_table_lookup(ptype->interfaces, ifname);
1134 }
1135
1136 PIL_rc
PILIncrIFRefCount(PILPluginUniv * mu,const char * interfacetype,const char * interfacename,int plusminus)1137 PILIncrIFRefCount(PILPluginUniv* mu
1138 , const char * interfacetype
1139 , const char * interfacename
1140 , int plusminus)
1141 {
1142 PILInterface* intf = FindIF(mu, interfacetype, interfacename);
1143
1144 if (intf) {
1145 g_assert(IS_PILINTERFACE(intf));
1146 IfIncrRefCount(intf, plusminus);
1147 return PIL_OK;
1148 }
1149 return PIL_NOPLUGIN;
1150 }
1151
1152 int
PILGetIFRefCount(PILPluginUniv * mu,const char * interfacetype,const char * interfacename)1153 PILGetIFRefCount(PILPluginUniv* mu
1154 , const char * interfacetype
1155 , const char * interfacename)
1156 {
1157 PILInterface* intf = FindIF(mu, interfacetype, interfacename);
1158
1159 return IfRefCount(intf);
1160 }
1161
1162 static void
IfForceUnregister(PILInterface * id)1163 IfForceUnregister(PILInterface *id)
1164 {
1165 if (DEBUGPLUGIN) {
1166 PILLog(PIL_DEBUG, "IfForceUnRegister(%s)"
1167 , id->interfacename);
1168 }
1169 RemoveAPILInterface(id);
1170 }
1171
1172 struct f_e_c_helper {
1173 gboolean(*fun)(PILInterface* clientif, void * passalong);
1174 void* passalong;
1175 };
1176
1177 static gboolean IfForEachClientHelper(gpointer key
1178 , gpointer iftype, gpointer helper_v);
1179
1180 static gboolean
IfForEachClientHelper(gpointer unused,gpointer iftype,gpointer v)1181 IfForEachClientHelper(gpointer unused, gpointer iftype, gpointer v)
1182 {
1183 struct f_e_c_helper* s = (struct f_e_c_helper*)v;
1184
1185 g_assert(IS_PILINTERFACE((PILInterface*)iftype));
1186 if (DEBUGPLUGIN) {
1187 PILLog(PIL_DEBUG, "IfForEachClientHelper(%s)"
1188 , ((PILInterface*)iftype)->interfacename);
1189 }
1190
1191 return s->fun((PILInterface*)iftype, s->passalong);
1192 }
1193
1194
1195 static void
IfForEachClientRemove(PILInterface * mgrif,gboolean (* f)(PILInterface * clientif,void * passalong),void * passalong)1196 IfForEachClientRemove
1197 ( PILInterface* mgrif
1198 , gboolean(*f)(PILInterface* clientif, void * passalong)
1199 , void* passalong /* usually PILInterface* */
1200 )
1201 {
1202 PILInterfaceType* mgrt;
1203 PILInterfaceUniv* u;
1204 const char * ifname;
1205 PILInterfaceType* clientt;
1206
1207 struct f_e_c_helper h = {f, passalong};
1208
1209
1210 if (mgrif == NULL || (mgrt = mgrif->interfacetype) == NULL
1211 || (u = mgrt->universe) == NULL
1212 || (ifname = mgrif->interfacename) == NULL) {
1213 PILLog(PIL_WARN, "bad parameters to IfForEachClientRemove");
1214 return;
1215 }
1216
1217 if ((clientt = g_hash_table_lookup(u->iftypes, ifname)) == NULL) {
1218 if (DEBUGPLUGIN) {
1219 PILLog(PIL_DEBUG
1220 , "Interface manager [%s/%s] has no clients"
1221 , PI_IFMANAGER, ifname);
1222 }
1223 return;
1224 };
1225 if (DEBUGPLUGIN) {
1226 PILLog(PIL_DEBUG, "IfForEachClientRemove(%s:%s)"
1227 , mgrt->typename, clientt->typename);
1228 }
1229 if (clientt->ifmgr_ref != mgrif) {
1230 PILLog(PIL_WARN, "Bad ifmgr_ref ptr in PILInterfaceType");
1231 return;
1232 }
1233
1234 g_hash_table_foreach_remove(clientt->interfaces, IfForEachClientHelper
1235 , &h);
1236 }
1237
1238 static PIL_rc
PILregister_plugin(PILPlugin * piinfo,const PILPluginOps * commonops)1239 PILregister_plugin(PILPlugin* piinfo, const PILPluginOps* commonops)
1240 {
1241 piinfo->pluginops = commonops;
1242
1243 return PIL_OK;
1244 }
1245
1246 static PIL_rc
PILunregister_plugin(PILPlugin * piinfo)1247 PILunregister_plugin(PILPlugin* piinfo)
1248 {
1249 if (DEBUGPLUGIN) {
1250 PILLog(PIL_DEBUG, "PILunregister_plugin(%s)"
1251 , piinfo->plugin_name);
1252 }
1253 RemoveAPILPlugin(piinfo);
1254 return PIL_OK;
1255 }
1256
1257 /* General logging function (not really UPPILS-specific) */
1258 static void
PILLog(PILLogLevel priority,const char * format,...)1259 PILLog(PILLogLevel priority, const char * format, ...)
1260 {
1261 va_list args;
1262 GLogLevelFlags flags;
1263
1264 switch(priority) {
1265 case PIL_FATAL: flags = G_LOG_LEVEL_ERROR;
1266 break;
1267 case PIL_CRIT: flags = G_LOG_LEVEL_CRITICAL;
1268 break;
1269
1270 default: /* FALL THROUGH... */
1271 case PIL_WARN: flags = G_LOG_LEVEL_WARNING;
1272 break;
1273
1274 case PIL_INFO: flags = G_LOG_LEVEL_INFO;
1275 break;
1276 case PIL_DEBUG: flags = G_LOG_LEVEL_DEBUG;
1277 break;
1278 };
1279 va_start (args, format);
1280 g_logv (G_LOG_DOMAIN, flags, format, args);
1281 va_end (args);
1282 }
1283
1284 static const char * PIL_strerrmsgs [] =
1285 { "Success"
1286 , "Invalid Parameters"
1287 , "Bad plugin/interface type"
1288 , "Duplicate entry (plugin/interface name/type)"
1289 , "Oops happens"
1290 , "No such plugin/interface/interface type"
1291 };
1292
1293 const char *
PIL_strerror(PIL_rc rc)1294 PIL_strerror(PIL_rc rc)
1295 {
1296 int irc = (int) rc;
1297 static char buf[128];
1298
1299 if (irc < 0 || irc >= DIMOF(PIL_strerrmsgs)) {
1300 snprintf(buf, sizeof(buf), "return code %d (?)", irc);
1301 return buf;
1302 }
1303 return PIL_strerrmsgs[irc];
1304 }
1305
1306 /*
1307 * Returns the PATHname of the file containing the requested plugin
1308 * This file handles PATH-like semantics from the rootdirlist.
1309 * It is also might be the right place to put alias handing in the future...
1310 */
1311 static char *
PILPluginPath(PILPluginUniv * universe,const char * plugintype,const char * pluginname)1312 PILPluginPath(PILPluginUniv* universe, const char * plugintype
1313 , const char * pluginname)
1314 {
1315 char * PluginPath = NULL;
1316 char ** spath_component;
1317
1318 for (spath_component = universe->rootdirlist; *spath_component
1319 ; ++ spath_component) {
1320
1321 if (PluginPath) {
1322 g_free(PluginPath); PluginPath=NULL;
1323 }
1324
1325 PluginPath = g_strdup_printf("%s%s%s%s%s%s"
1326 , *spath_component
1327 , G_DIR_SEPARATOR_S
1328 , plugintype
1329 , G_DIR_SEPARATOR_S
1330 , pluginname
1331 , PLUGINSUFFIX);
1332 if (DEBUGPLUGIN) {
1333 PILLog(PIL_DEBUG
1334 , "PILS: Looking for %s/%s => [%s]"
1335 , plugintype, pluginname, PluginPath);
1336 }
1337
1338 if (PluginExists(PluginPath) == PIL_OK) {
1339 if (DEBUGPLUGIN) {
1340 PILLog(PIL_DEBUG
1341 , "Plugin path for %s/%s => [%s]"
1342 , plugintype, pluginname, PluginPath);
1343 }
1344 return PluginPath;
1345 }
1346 /* FIXME: Put alias file processing here... */
1347 }
1348
1349 /* Can't find 'em all... */
1350 return PluginPath;
1351 }
1352
1353 static PIL_rc
PluginExists(const char * PluginPath)1354 PluginExists(const char * PluginPath)
1355 {
1356 /* Make sure we can read and execute the plugin file */
1357 /* This test is nice, because dlopen reasons aren't return codes */
1358
1359 if (access(PluginPath, R_OK) != 0) {
1360 if (DEBUGPLUGIN) {
1361 PILLog(PIL_DEBUG, "Plugin file %s does not exist"
1362 , PluginPath);
1363 }
1364 return PIL_NOPLUGIN;
1365 }
1366 return PIL_OK;
1367 }
1368
1369 /* Return PIL_OK if the given plugin exists */
1370 PIL_rc
PILPluginExists(PILPluginUniv * piuniv,const char * plugintype,const char * pluginname)1371 PILPluginExists(PILPluginUniv* piuniv
1372 , const char * plugintype
1373 , const char * pluginname)
1374 {
1375 PIL_rc rc;
1376 char * path = PILPluginPath(piuniv, plugintype, pluginname);
1377
1378 if (path == NULL) {
1379 return PIL_INVAL;
1380 }
1381 rc = PluginExists(path);
1382 DELETE(path);
1383 return rc;
1384 }
1385
1386 /*
1387 * PILLoadPlugin() - loads a plugin into memory and calls the
1388 * initial() entry point in the plugin.
1389 *
1390 *
1391 * Method:
1392 *
1393 * Construct file name of plugin.
1394 * See if plugin exists. If not, fail with PIL_NOPLUGIN.
1395 *
1396 * Search Universe for plugin type
1397 * If found, search plugin type for pluginname
1398 * if found, fail with PIL_EXIST.
1399 * Otherwise,
1400 * Create new Plugin type structure
1401 * Use lt_dlopen() on plugin to get lt_dlhandle for it.
1402 *
1403 * Construct the symbol name of the initialization function.
1404 *
1405 * Use lt_dlsym() to find the pointer to the init function.
1406 *
1407 * Call the initialization function.
1408 */
1409 PIL_rc
PILLoadPlugin(PILPluginUniv * universe,const char * plugintype,const char * pluginname,void * plugin_user_data)1410 PILLoadPlugin(PILPluginUniv* universe, const char * plugintype
1411 , const char * pluginname
1412 , void* plugin_user_data)
1413 {
1414 PIL_rc rc;
1415 char * PluginPath;
1416 char * PluginSym;
1417 PILPluginType* pitype;
1418 PILPlugin* piinfo;
1419 lt_dlhandle dlhand;
1420 PILPluginInitFun initfun;
1421
1422 PluginPath = PILPluginPath(universe, plugintype, pluginname);
1423
1424 if ((rc=PluginExists(PluginPath)) != PIL_OK) {
1425 DELETE(PluginPath);
1426 return rc;
1427 }
1428
1429 if((pitype=g_hash_table_lookup(universe->PluginTypes, plugintype))
1430 != NULL) {
1431 if ((piinfo = g_hash_table_lookup
1432 ( pitype->Plugins, pluginname)) != NULL) {
1433
1434 if (DEBUGPLUGIN) {
1435 PILLog(PIL_DEBUG, "Plugin %s already loaded"
1436 , PluginPath);
1437 }
1438 DELETE(PluginPath);
1439 return PIL_EXIST;
1440 }
1441 if (DEBUGPLUGIN) {
1442 PILLog(PIL_DEBUG, "PluginType %s already present"
1443 , plugintype);
1444 }
1445 }else{
1446 if (DEBUGPLUGIN) {
1447 PILLog(PIL_DEBUG, "Creating PluginType for %s"
1448 , plugintype);
1449 }
1450 /* Create a new PILPluginType object */
1451 pitype = NewPILPluginType(universe, plugintype);
1452 }
1453
1454 g_assert(pitype != NULL);
1455
1456 /*
1457 * At this point, we have a PILPluginType object and our
1458 * plugin name is not listed in it.
1459 */
1460
1461 dlhand = lt_dlopen(PluginPath);
1462
1463 if (!dlhand) {
1464 PILLog(PIL_WARN
1465 , "lt_dlopen() failure on plugin %s/%s [%s]."
1466 " Reason: [%s]"
1467 , plugintype, pluginname
1468 , PluginPath
1469 , lt_dlerror());
1470 DELETE(PluginPath);
1471 return PIL_NOPLUGIN;
1472 }
1473 DELETE(PluginPath);
1474 /* Construct the magic init function symbol name */
1475 PluginSym = g_strdup_printf(PIL_FUNC_FMT
1476 , plugintype, pluginname);
1477 if (DEBUGPLUGIN) {
1478 PILLog(PIL_DEBUG, "Plugin %s/%s init function: %s"
1479 , plugintype, pluginname
1480 , PluginSym);
1481 }
1482
1483 initfun = lt_dlsym(dlhand, PluginSym);
1484
1485 if (initfun == NULL) {
1486 PILLog(PIL_WARN
1487 , "Plugin %s/%s init function (%s) not found"
1488 , plugintype, pluginname, PluginSym);
1489 DELETE(PluginSym);
1490 lt_dlclose(dlhand); dlhand=NULL;
1491 DelPILPluginType(pitype);
1492 return PIL_NOPLUGIN;
1493 }
1494 DELETE(PluginSym);
1495 /*
1496 * Construct the new PILPlugin object
1497 */
1498 piinfo = NewPILPlugin(pitype, pluginname, dlhand, initfun);
1499 g_assert(piinfo != NULL);
1500 g_hash_table_insert(pitype->Plugins, g_strdup(piinfo->plugin_name), piinfo);
1501 if (DEBUGPLUGIN) {
1502 PILLog(PIL_DEBUG, "Plugin %s/%s loaded and constructed."
1503 , plugintype, pluginname);
1504 }
1505 if (DEBUGPLUGIN) {
1506 PILLog(PIL_DEBUG, "Calling init function in plugin %s/%s."
1507 , plugintype, pluginname);
1508 }
1509 /* Save away the user_data for later */
1510 piinfo->ud_plugin = plugin_user_data;
1511 /* initfun is allowed to change ud_plugin if they want */
1512 initfun(piinfo, universe->imports, plugin_user_data);
1513
1514 return PIL_OK;
1515 }/*PILLoadPlugin*/
1516
1517
1518
1519 #define REPORTERR(msg) PILLog(PIL_CRIT, "%s", msg)
1520
1521 /*
1522 * Register an interface.
1523 *
1524 * This function is exported to plugins for their use.
1525 */
1526 static PIL_rc
PILRegisterInterface(PILPlugin * piinfo,const char * interfacetype,const char * interfacename,void * Ops,PILInterfaceFun close_func,PILInterface ** interfaceid,void ** Imports,void * ud_interface)1527 PILRegisterInterface(PILPlugin* piinfo
1528 , const char * interfacetype /* Type of interface */
1529 , const char * interfacename /* Name of interface */
1530 , void* Ops /* Info (functions) exported
1531 by this interface */
1532 , PILInterfaceFun close_func /* Close function for interface */
1533 , PILInterface** interfaceid /* Interface id (OP) */
1534 , void** Imports /* Functions imported by
1535 this interface (OP) */
1536 , void* ud_interface /* Optional user_data */
1537 )
1538 {
1539 PILPluginUniv* piuniv; /* Universe this plugin is in */
1540 PILPluginType* pitype; /* Type of this plugin */
1541 PILInterfaceUniv* ifuniv; /* Universe this interface is in */
1542 PILInterfaceType*iftype; /* Type of this interface */
1543 PILInterface* ifinfo; /* Info about this Interface */
1544
1545 PILInterfaceType*ifmgrtype; /* PILInterfaceType for PI_IFMANAGER */
1546 PILInterface* ifmgrinfo; /* Interf info for "interfacetype" */
1547 const PILInterfaceOps* ifops; /* Ops vector for InterfaceManager */
1548 /* of type "interfacetype" */
1549 PIL_rc rc;
1550
1551 if ( piinfo == NULL
1552 || (pitype = piinfo->plugintype) == NULL
1553 || (piuniv = pitype->piuniv) == NULL
1554 || (ifuniv = piuniv->ifuniv) == NULL
1555 || ifuniv->iftypes == NULL
1556 ) {
1557 REPORTERR("bad parameters to PILRegisterInterface");
1558 return PIL_INVAL;
1559 }
1560
1561 /* Now we have lots of info, but not quite enough... */
1562
1563 if ((iftype = g_hash_table_lookup(ifuniv->iftypes, interfacetype))
1564 == NULL) {
1565
1566 /* Try to autoload the needed interface handler */
1567 rc = PILLoadPlugin(piuniv, PI_IFMANAGER, interfacetype, NULL);
1568
1569 /* See if the interface handler loaded like we expect */
1570 if ((iftype = g_hash_table_lookup(ifuniv->iftypes
1571 , interfacetype)) == NULL) {
1572 return PIL_BADTYPE;
1573 }
1574 }
1575 if ((ifinfo = g_hash_table_lookup(iftype->interfaces, interfacename))
1576 != NULL) {
1577 g_warning("Attempt to register duplicate interface: %s/%s"
1578 , interfacetype, interfacename);
1579 return PIL_EXIST;
1580 }
1581 /*
1582 * OK... Now we know it is valid, and isn't registered...
1583 * Let's locate the InterfaceManager registrar for this type
1584 */
1585 if ((ifmgrtype = g_hash_table_lookup(ifuniv->iftypes, PI_IFMANAGER))
1586 == NULL) {
1587 REPORTERR("No " PI_IFMANAGER " type!");
1588 return PIL_OOPS;
1589 }
1590 if ((ifmgrinfo = g_hash_table_lookup(ifmgrtype->interfaces
1591 , interfacetype)) == NULL) {
1592 PILLog(PIL_CRIT
1593 , "No interface manager for given type (%s) !"
1594 , interfacetype);
1595 return PIL_BADTYPE;
1596 }
1597
1598 ifops = ifmgrinfo->exports;
1599
1600 /* Now we have all the information anyone could possibly want ;-) */
1601
1602 ifinfo = NewPILInterface(iftype, interfacename, Ops
1603 , close_func, ud_interface, piinfo);
1604
1605 g_assert(ifmgrinfo == ifinfo->ifmanager);
1606 *interfaceid = ifinfo;
1607
1608 /* Call the registration function for our interface type */
1609 rc = ifops->RegisterInterface(ifinfo, Imports);
1610
1611
1612 /* Increment reference count of interface manager */
1613 IfIncrRefCount(ifmgrinfo, 1);
1614
1615 /* Increment the ref count of the plugin that loaded us */
1616 PluginIncrRefCount(piinfo, 1);
1617
1618 if (rc != PIL_OK) {
1619 RemoveAPILInterface(ifinfo);
1620 }
1621 return rc;
1622 }
1623
1624 /*
1625 * Method:
1626 *
1627 * Verify interface is valid.
1628 *
1629 * Call interface close function.
1630 *
1631 * Call interface manager unregister function
1632 *
1633 * Call RmAPILInterface to remove from InterfaceType table, and
1634 * free interface object.
1635 *
1636 */
1637
1638 static PIL_rc
PILunregister_interface(PILInterface * id)1639 PILunregister_interface(PILInterface* id)
1640 {
1641 PILInterfaceType* t;
1642 PILInterfaceUniv* u;
1643 PIL_rc rc;
1644 PILInterface* ifmgr_info; /* Pointer to our interface handler */
1645 const PILInterfaceOps* exports; /* InterfaceManager operations for
1646 * the type of interface we are
1647 */
1648
1649 if ( id == NULL
1650 || (t = id->interfacetype) == NULL
1651 || (u = t->universe) == NULL
1652 || id->interfacename == NULL) {
1653 PILLog(PIL_WARN, "PILunregister_interface: bad interfaceid");
1654 return PIL_INVAL;
1655 }
1656 if (DEBUGPLUGIN) {
1657 PILLog(PIL_DEBUG, "PILunregister_interface(%s/%s)"
1658 , t->typename, id->interfacename);
1659 }
1660 PILValidateInterface(NULL, id, t);
1661 PILValidateInterfaceType(NULL, t, u);
1662 if (DEBUGPLUGIN) {
1663 PILLog(PIL_DEBUG, "Calling InterfaceClose on %s/%s"
1664 , t->typename, id->interfacename);
1665 }
1666
1667 /* Call the close function supplied by the interface */
1668
1669 if ((id->if_close != NULL)
1670 && ((rc=id->if_close(id, id->ud_interface)) != PIL_OK)) {
1671 PILLog(PIL_WARN, "InterfaceClose on %s/%s returned %s"
1672 , t->typename, id->interfacename
1673 , PIL_strerror(rc));
1674 } else {
1675 rc = PIL_OK;
1676 }
1677
1678 /* Find the InterfaceManager that manages us */
1679 ifmgr_info = t->ifmgr_ref;
1680
1681 g_assert(ifmgr_info != NULL);
1682
1683 /* Find the exported functions from that IFIF */
1684 exports = ifmgr_info->exports;
1685
1686 g_assert(exports != NULL && exports->UnRegisterInterface != NULL);
1687
1688 /* Call the interface manager unregister function */
1689 exports->UnRegisterInterface(id);
1690
1691 /* Decrement reference count of interface manager */
1692 IfIncrRefCount(ifmgr_info, -1);
1693 /* This may make ifmgr_info invalid */
1694 ifmgr_info = NULL;
1695
1696 /* Decrement the reference count of the plugin that loaded us */
1697 PluginIncrRefCount(id->loadingpi, -1);
1698
1699 return rc;
1700 }
1701
1702 static PILInterfaceUniv*
NewPILInterfaceUniv(PILPluginUniv * piuniv)1703 NewPILInterfaceUniv(PILPluginUniv* piuniv)
1704 {
1705 PILInterfaceUniv* ret = NEW(PILInterfaceUniv);
1706 static int ltinityet = 0;
1707
1708 if (DEBUGPLUGIN) {
1709 PILLog(PIL_DEBUG, "NewPILInterfaceUniv(0x%lx)"
1710 , (unsigned long)ret);
1711 }
1712 if (!ltinityet) {
1713 ltinityet=1;
1714 lt_dlinit();
1715 }
1716 STATNEW(interfaceuniv);
1717 ret->MagicNum = PIL_MAGIC_INTERFACEUNIV;
1718 /* Make the two universes point at each other */
1719 ret->piuniv = piuniv;
1720 piuniv->ifuniv = ret;
1721
1722 ret->iftypes = g_hash_table_new(g_str_hash, g_str_equal);
1723
1724 InterfaceManager_plugin_init(piuniv);
1725 return ret;
1726 }
1727
1728 static void
DelPILInterfaceUniv(PILInterfaceUniv * ifuniv)1729 DelPILInterfaceUniv(PILInterfaceUniv* ifuniv)
1730 {
1731 PILInterfaceType* ifmgrtype;
1732 g_assert(ifuniv!= NULL && ifuniv->iftypes != NULL);
1733 PILValidateInterfaceUniv(NULL, ifuniv, NULL);
1734
1735 STATFREE(interfaceuniv);
1736 if (DEBUGPLUGIN) {
1737 PILLog(PIL_DEBUG, "DelPILInterfaceUniv(0x%lx)"
1738 , (unsigned long) ifuniv);
1739 }
1740 g_hash_table_foreach_remove(ifuniv->iftypes, RmAPILInterfaceType, NULL);
1741 if (DEBUGPLUGIN) {
1742 PILLog(PIL_DEBUG, "DelPILInterfaceUniv: final cleanup");
1743 }
1744 ifmgrtype = g_hash_table_lookup(ifuniv->iftypes, PI_IFMANAGER);
1745 RemoveAPILInterfaceType(ifmgrtype, ifmgrtype);
1746 /*
1747 * FIXME! need to delete the interface for PI_IFMANAGER last
1748 * Right now, it seems to happen last, but I think that's
1749 * coincidence...
1750 */
1751 g_hash_table_destroy(ifuniv->iftypes);
1752 ZAP(ifuniv);
1753 DELETE(ifuniv);
1754 }
1755
1756 /*
1757 * These RmA* functions primarily called from hash_table_foreach,
1758 * so they have gpointer arguments. This *not necessarily* clause
1759 * is why they do the g_hash_table_lookup_extended call instead of
1760 * just deleting the key. When called from outside, the key
1761 * may not be pointing at the key to actually free, but a copy
1762 * of the key.
1763 */
1764 static gboolean /* IsA GHFunc: required for g_hash_table_foreach_remove() */
RmAPILInterfaceType(gpointer typename,gpointer iftype,gpointer notused)1765 RmAPILInterfaceType
1766 ( gpointer typename /* Name of this interface type */
1767 , gpointer iftype /* PILInterfaceType* */
1768 , gpointer notused
1769 )
1770 {
1771 PILInterfaceType* Iftype = iftype;
1772 PILInterfaceUniv* Ifuniv = Iftype->universe;
1773
1774 /*
1775 * We are not always called by g_hash_table_foreach_remove()
1776 */
1777
1778 g_assert(IS_PILINTERFACETYPE(Iftype));
1779 PILValidateInterfaceUniv(NULL, Ifuniv, NULL);
1780 if (DEBUGPLUGIN) {
1781 PILLog(PIL_DEBUG, "RmAPILInterfaceType(%s)"
1782 , (char*)typename);
1783 }
1784 if (iftype != notused
1785 && strcmp(Iftype->typename, PI_IFMANAGER) == 0) {
1786 if (DEBUGPLUGIN) {
1787 PILLog(PIL_DEBUG, "RmAPILInterfaceType: skipping (%s)"
1788 , (char*)typename);
1789 }
1790 return FALSE;
1791 }
1792
1793 DelPILInterfaceType(iftype);
1794 DELETE(typename);
1795
1796 return TRUE;
1797 }
1798
1799 static void
RemoveAPILInterfaceType(PILInterfaceType * Iftype,PILInterfaceType * t2)1800 RemoveAPILInterfaceType(PILInterfaceType*Iftype, PILInterfaceType* t2)
1801 {
1802 PILInterfaceUniv* Ifuniv = Iftype->universe;
1803 gpointer key;
1804
1805 if (DEBUGPLUGIN) {
1806 PILLog(PIL_DEBUG, "RemoveAPILInterfaceType(%s)"
1807 , Iftype->typename);
1808 }
1809 if (t2 != Iftype
1810 && strcmp(Iftype->typename, PI_IFMANAGER) == 0) {
1811 PILLog(PIL_DEBUG, "RemoveAPILInterfaceType: skipping (%s)"
1812 , Iftype->typename);
1813 return;
1814 }
1815 if (g_hash_table_lookup_extended(Ifuniv->iftypes
1816 , Iftype->typename, &key, (gpointer)&Iftype)) {
1817
1818 g_hash_table_remove(Ifuniv->iftypes, key);
1819 RmAPILInterfaceType(key, Iftype, t2);
1820 }else{
1821 g_assert_not_reached();
1822 }
1823 }
1824
1825 /*
1826 * We need to write more functions: These include...
1827 *
1828 * Plugin functions:
1829 *
1830 * PILPluginPath() - returns path name for a given plugin
1831 *
1832 * PILPluginTypeList() - returns list of plugins of a given type
1833 *
1834 */
1835 static void free_dirlist(struct dirent** dlist, int n);
1836
1837 static int qsort_string_cmp(const void *a, const void *b);
1838
1839
1840 static void
free_dirlist(struct dirent ** dlist,int n)1841 free_dirlist(struct dirent** dlist, int n)
1842 {
1843 int j;
1844 for (j=0; j < n; ++j) {
1845 if (dlist[j]) {
1846 free(dlist[j]);
1847 dlist[j] = NULL;
1848 }
1849 }
1850 free(dlist);
1851 }
1852
1853 static int
qsort_string_cmp(const void * a,const void * b)1854 qsort_string_cmp(const void *a, const void *b)
1855 {
1856 return(strcmp(*(const char * const *)a, *(const char * const *)b));
1857 }
1858
1859 #define FREE_DIRLIST(dlist, n) {free_dirlist(dlist, n); dlist = NULL;}
1860
1861 static int
so_select(const struct dirent * dire)1862 so_select (const struct dirent *dire)
1863 {
1864
1865 const char obj_end [] = PLUGINSUFFIX;
1866 const char *end = &dire->d_name[strlen(dire->d_name)
1867 - (STRLEN_CONST(obj_end))];
1868
1869
1870 if (DEBUGPLUGIN) {
1871 PILLog(PIL_DEBUG, "In so_select: %s.", dire->d_name);
1872 }
1873 if (end < dire->d_name) {
1874 return 0;
1875 }
1876 if (strcmp(end, obj_end) == 0) {
1877 if (DEBUGPLUGIN) {
1878 PILLog(PIL_DEBUG, "FILE %s looks like a plugin name."
1879 , dire->d_name);
1880 }
1881 return 1;
1882 }
1883 if (DEBUGPLUGIN) {
1884 PILLog(PIL_DEBUG
1885 , "FILE %s Doesn't look like a plugin name [%s] "
1886 "%zd %zd %s."
1887 , dire->d_name, end
1888 , sizeof(obj_end), strlen(dire->d_name)
1889 , &dire->d_name[strlen(dire->d_name)
1890 - (STRLEN_CONST(obj_end))]);
1891 }
1892
1893 return 0;
1894 }
1895
1896 /* Return (sorted) list of available plugin names */
1897 static char**
PILPluginTypeListPlugins(PILPluginType * pitype,int * picount)1898 PILPluginTypeListPlugins(PILPluginType* pitype
1899 , int * picount /* Can be NULL ... */)
1900 {
1901 const char * piclass = pitype->plugintype;
1902 unsigned plugincount = 0;
1903 char ** result = NULL;
1904 int initoff = 0;
1905 char ** pelem;
1906
1907 /* Return all the plugins in all the directories in the PATH */
1908
1909 for (pelem=pitype->piuniv->rootdirlist; *pelem; ++pelem) {
1910 int j;
1911 GString* path;
1912 int dircount;
1913 struct dirent** files;
1914
1915
1916 path = g_string_new(*pelem);
1917 g_assert(piclass != NULL);
1918 if (piclass) {
1919 if (g_string_append_c(path, G_DIR_SEPARATOR) == NULL
1920 || g_string_append(path, piclass) == NULL) {
1921 g_string_free(path, 1); path = NULL;
1922 return(NULL);
1923 }
1924 }
1925
1926 files = NULL;
1927 errno = 0;
1928 dircount = scandir(path->str, &files
1929 , SCANSEL_CAST so_select, NULL);
1930 if (DEBUGPLUGIN) {
1931 PILLog(PIL_DEBUG, "PILS: Examining directory [%s]"
1932 ": [%d] files matching [%s] suffix found."
1933 , path->str, dircount, PLUGINSUFFIX);
1934 }
1935 g_string_free(path, 1); path=NULL;
1936
1937 if (dircount <= 0) {
1938 if (files != NULL) {
1939 FREE_DIRLIST(files, dircount);
1940 files = NULL;
1941 }
1942 if (DEBUGPLUGIN) {
1943 PILLog(PIL_DEBUG
1944 , "PILS: skipping empty directory"
1945 " in PILPluginTypeListPlugins()");
1946 }
1947 continue;
1948 }
1949
1950 initoff = plugincount;
1951 plugincount += dircount;
1952 if (result == NULL) {
1953 result = (char **) g_malloc((plugincount+1)*sizeof(char *));
1954 }else{
1955 result = (char **) g_realloc(result
1956 , (plugincount+1)*sizeof(char *));
1957 }
1958
1959 for (j=0; j < dircount; ++j) {
1960 char* s;
1961 unsigned slen = strlen(files[j]->d_name)
1962 - STRLEN_CONST(PLUGINSUFFIX);
1963
1964 s = g_malloc(slen+1);
1965 strncpy(s, files[j]->d_name, slen);
1966 s[slen] = EOS;
1967 result[initoff+j] = s;
1968 if (DEBUGPLUGIN) {
1969 PILLog(PIL_DEBUG, "PILS: plugin [%s] found"
1970 , s);
1971 }
1972 }
1973 FREE_DIRLIST(files, dircount);
1974 files = NULL;
1975 }
1976
1977 if (picount != NULL) {
1978 *picount = plugincount;
1979 }
1980 if (result) {
1981 result[plugincount] = NULL;
1982 /* Return them in sorted order... */
1983 qsort(result, plugincount, sizeof(char *), qsort_string_cmp);
1984 }else{
1985 if (DEBUGPLUGIN) {
1986 PILLog(PIL_DEBUG, "PILS: NULL return"
1987 " from PILPluginTypeListPlugins()");
1988 }
1989 }
1990
1991
1992 return result;
1993 }
1994 /* Return (sorted) list of available plugin names */
1995 char**
PILListPlugins(PILPluginUniv * u,const char * pitype,int * picount)1996 PILListPlugins(PILPluginUniv* u, const char * pitype
1997 , int * picount /* Can be NULL ... */)
1998 {
1999 PILPluginType* t;
2000 if ((t = g_hash_table_lookup(u->PluginTypes, pitype)) == NULL) {
2001 if (picount) {
2002 *picount = 0;
2003 }
2004 t = NewPILPluginType(u, pitype);
2005 if (!t) {
2006 return NULL;
2007 }
2008 }
2009 return PILPluginTypeListPlugins(t, picount);
2010 }
2011
2012 void
PILFreePluginList(char ** pluginlist)2013 PILFreePluginList(char ** pluginlist)
2014 {
2015 char ** ml = pluginlist;
2016
2017 if (!ml) {
2018 return;
2019 }
2020
2021 while (*ml != NULL) {
2022 DELETE(*ml);
2023 }
2024 DELETE(pluginlist);
2025 }
2026
2027
2028 static void
PILValidatePlugin(gpointer key,gpointer plugin,gpointer pitype)2029 PILValidatePlugin(gpointer key, gpointer plugin, gpointer pitype)
2030 {
2031 const char * Key = key;
2032 const PILPlugin * Plugin = plugin;
2033
2034 g_assert(IS_PILPLUGIN(Plugin));
2035
2036 g_assert(Key == NULL || strcmp(Key, Plugin->plugin_name) == 0);
2037
2038 g_assert (Plugin->refcnt >= 0 );
2039
2040 /* g_assert (Plugin->pluginops != NULL ); */
2041 g_assert (strcmp(Key, PI_IFMANAGER) == 0 || Plugin->dlinitfun != NULL );
2042 g_assert (strcmp(Plugin->plugin_name, PI_IFMANAGER) == 0
2043 || Plugin->dlhandle != NULL);
2044 g_assert(Plugin->plugintype != NULL);
2045 g_assert(IS_PILPLUGINTYPE(Plugin->plugintype));
2046 g_assert(pitype == NULL || pitype == Plugin->plugintype);
2047 }
2048
2049 static void
PILValidatePluginType(gpointer key,gpointer pitype,gpointer piuniv)2050 PILValidatePluginType(gpointer key, gpointer pitype, gpointer piuniv)
2051 {
2052 char * Key = key;
2053 PILPluginType * Pitype = pitype;
2054 PILPluginUniv * Muniv = piuniv;
2055
2056 g_assert(IS_PILPLUGINTYPE(Pitype));
2057 g_assert(Muniv == NULL || IS_PILPLUGINUNIV(Muniv));
2058 g_assert(Key == NULL || strcmp(Key, Pitype->plugintype) == 0);
2059 g_assert(IS_PILPLUGINUNIV(Pitype->piuniv));
2060 g_assert(piuniv == NULL || piuniv == Pitype->piuniv);
2061 g_assert(Pitype->Plugins != NULL);
2062 g_hash_table_foreach(Pitype->Plugins, PILValidatePlugin, Pitype);
2063 }
2064 static void
PILValidatePluginUniv(gpointer key,gpointer piuniv,gpointer dummy)2065 PILValidatePluginUniv(gpointer key, gpointer piuniv, gpointer dummy)
2066 {
2067 PILPluginUniv * Muniv = piuniv;
2068
2069 g_assert(IS_PILPLUGINUNIV(Muniv));
2070 g_assert(Muniv->rootdirlist != NULL);
2071 g_assert(Muniv->imports != NULL);
2072 g_hash_table_foreach(Muniv->PluginTypes, PILValidatePluginType, piuniv);
2073 PILValidateInterfaceUniv(NULL, Muniv->ifuniv, piuniv);
2074 }
2075 static void
PILValidateInterface(gpointer key,gpointer interface,gpointer iftype)2076 PILValidateInterface(gpointer key, gpointer interface, gpointer iftype)
2077 {
2078 char * Key = key;
2079 PILInterface* Interface = interface;
2080 g_assert(IS_PILINTERFACE(Interface));
2081 g_assert(Key == NULL || strcmp(Key, Interface->interfacename) == 0);
2082 g_assert(IS_PILINTERFACETYPE(Interface->interfacetype));
2083 g_assert(iftype == NULL || iftype == Interface->interfacetype);
2084 g_assert(Interface->ifmanager!= NULL);
2085 g_assert(IS_PILINTERFACE(Interface->ifmanager));
2086 g_assert(strcmp(Interface->interfacetype->typename
2087 , Interface->ifmanager->interfacename)== 0);
2088 g_assert(Interface->exports != NULL);
2089 }
2090 static void
PILValidateInterfaceType(gpointer key,gpointer iftype,gpointer ifuniv)2091 PILValidateInterfaceType(gpointer key, gpointer iftype, gpointer ifuniv)
2092 {
2093 char * Key = key;
2094 PILInterfaceType* Iftype = iftype;
2095 g_assert(IS_PILINTERFACETYPE(Iftype));
2096 g_assert(Key == NULL || strcmp(Key, Iftype->typename) == 0);
2097 g_assert(ifuniv == NULL || Iftype->universe == ifuniv);
2098 g_assert(Iftype->interfaces != NULL);
2099 g_assert(Iftype->ifmgr_ref != NULL);
2100 g_assert(IS_PILINTERFACE(Iftype->ifmgr_ref));
2101 g_assert(Key == NULL || strcmp(Key, Iftype->ifmgr_ref->interfacename) == 0);
2102
2103 g_hash_table_foreach(Iftype->interfaces, PILValidateInterface, iftype);
2104 }
2105 static void
PILValidateInterfaceUniv(gpointer key,gpointer ifuniv,gpointer piuniv)2106 PILValidateInterfaceUniv(gpointer key, gpointer ifuniv, gpointer piuniv)
2107 {
2108 PILInterfaceUniv* Ifuniv = ifuniv;
2109 PILPluginUniv* Pluginuniv = piuniv;
2110 g_assert(IS_PILINTERFACEUNIV(Ifuniv));
2111 g_assert(Pluginuniv == NULL || IS_PILPLUGINUNIV(Pluginuniv));
2112 g_assert(piuniv == NULL || piuniv == Ifuniv->piuniv);
2113 g_hash_table_foreach(Ifuniv->iftypes, PILValidateInterfaceType, ifuniv);
2114 }
2115
2116 #define PRSTAT(type) { \
2117 PILLog(PIL_INFO, "Plugin system objects (" #type "): " \
2118 "\tnew %ld free \%ld current %ld" \
2119 , PILstats.type.news \
2120 , PILstats.type.frees \
2121 , PILstats.type.news - PILstats.type.frees); \
2122 }
2123 void
PILLogMemStats(void)2124 PILLogMemStats(void)
2125 {
2126 PRSTAT(plugin);
2127 PRSTAT(pitype);
2128 PRSTAT(piuniv);
2129 PRSTAT(interface);
2130 PRSTAT(interfacetype);
2131 PRSTAT(interfaceuniv);
2132 }
2133
2134 /*
2135 * Function for logging with the given logging function
2136 * The reason why it's here is so we can get printf arg checking
2137 * You can't get that when you call a function pointer directly.
2138 */
2139 void
PILCallLog(PILLogFun logfun,PILLogLevel priority,const char * fmt,...)2140 PILCallLog(PILLogFun logfun, PILLogLevel priority, const char * fmt, ...)
2141 {
2142 va_list args;
2143 char * str;
2144 int err = errno;
2145
2146 va_start (args, fmt);
2147 str = g_strdup_vprintf(fmt, args);
2148 va_end (args);
2149 logfun(priority, "%s", str);
2150 g_free(str);
2151 errno = err;
2152 }
2153