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