filename | src/plugin.c |
changeset | 1075:1a21750d300c |
prev | 1071:182cfe43c09e |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Mon Jan 30 20:11:08 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Replace wordexp() with a hand-coded env-var substitution. More portable, and avoids bugs with some wordexp() implementations |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Plugin loader code
5 *
6 * Copyright (c) 2009 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #include <sys/stat.h>
20 #include <dirent.h>
21 #include <dlfcn.h>
22 #include <string.h>
23 #include <glib/gmem.h>
24 #include <glib/gstrfuncs.h>
25 #include "plugin.h"
26 #include "lxpaths.h"
28 #ifdef APPLE_BUILD
29 #define SOEXT ".dylib"
30 #else
31 #define SOEXT ".so"
32 #endif
34 /** Dummy plugin used as a plugin directory marker */
35 #define DUMMY_PLUGIN ("lxdream_dummy" SOEXT)
37 const char *plugin_type_string[] = { "undefined", "audio driver", "input driver" };
39 int main(int argc, char *argv[]);
40 static const char *exec_path = NULL;
42 /**
43 * Return the full path to the main binary
44 */
45 static const char *get_exec_path()
46 {
47 if( exec_path == NULL ) {
48 Dl_info dli;
50 /* Use dladdr for this, since it should be available for any platform
51 * that we can support plugins on at all.
52 */
53 if( dladdr( main, &dli) ) {
54 gchar *path = g_strdup( dli.dli_fname );
55 char *i = strrchr( path, '/' );
56 if( i > path ) {
57 *i = '\0';
58 exec_path = path;
59 } else {
60 g_free(path);
61 }
62 }
63 }
64 return exec_path;
65 }
67 static gboolean plugin_load( const gchar *plugin_path )
68 {
69 void *so = dlopen(plugin_path, RTLD_NOW|RTLD_LOCAL);
70 if( so == NULL ) {
71 WARN("Failed to load plugin '%s': %s", plugin_path, dlerror());
72 return FALSE;
73 }
75 struct plugin_struct *plugin = (struct plugin_struct *)dlsym(so,"lxdream_plugin_entry");
76 if( plugin == NULL ) {
77 WARN("Failed to load plugin: '%s': Not an lxdream plugin", plugin_path);
78 dlclose(so);
79 return FALSE;
80 }
82 if( strcmp(lxdream_short_version, plugin->version) != 0 ) {
83 WARN("Failed to load plugin: '%s': Incompatible version (%s)", plugin_path, plugin->version);
84 dlclose(so);
85 return FALSE;
86 }
88 if( plugin->type == PLUGIN_NONE ) {
89 /* 'dummy' plugin - we don't actually want to load it */
90 dlclose(so);
91 return FALSE;
92 }
94 if( plugin->type < PLUGIN_MIN_TYPE || plugin->type > PLUGIN_MAX_TYPE ) {
95 WARN("Failed to load plugin: '%s': Unrecognized plugin type (%d)", plugin_path, plugin->type );
96 dlclose(so);
97 return FALSE;
98 }
100 if( plugin->register_plugin() == FALSE ) {
101 WARN("Failed to load plugin: '%s': Initialization failed", plugin_path);
102 dlclose(so);
103 return FALSE;
104 }
105 DEBUG("Loaded %s '%s'", plugin_type_string[plugin->type], plugin->name);
106 return TRUE;
107 }
109 static gboolean has_plugins( const gchar *path )
110 {
111 struct stat st;
113 gchar *dummy_name = g_strdup_printf( "%s/%s", path, DUMMY_PLUGIN );
114 if( stat( dummy_name, &st ) == 0 ) {
115 return TRUE;
116 } else {
117 return FALSE;
118 }
119 }
121 /**
122 * Scan the plugin dir and load all valid plugins.
123 */
124 static int plugin_load_all( const gchar *plugin_dir )
125 {
126 int plugin_count = 0;
127 struct dirent *ent;
129 DIR *dir = opendir(plugin_dir);
130 if( dir == NULL ) {
131 WARN( "Unable to open plugin directory '%s'", plugin_dir );
132 return 0;
133 }
135 while( (ent = readdir(dir)) != NULL ) {
136 const char *ext = strrchr(ent->d_name, '.');
137 if( ext != NULL && strcasecmp(SOEXT,ext) == 0 ) {
138 char *libname = g_strdup_printf( "%s/%s", plugin_dir,ent->d_name );
139 if( plugin_load( libname ) ) {
140 plugin_count++;
141 }
142 g_free(libname);
143 }
144 }
145 return plugin_count;
146 }
148 int plugin_init()
149 {
150 const char *path = get_exec_path();
151 if( path == NULL || !has_plugins(path) ) {
152 path = get_plugin_path();
153 }
155 DEBUG( "Plugin directory: %s", path );
156 return plugin_load_all( path );
157 }
.