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