Search
lxdream.org :: lxdream/src/plugin.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/plugin.c
changeset 1041:5fcc39857c5c
prev1027:4e527bc96109
next1071:182cfe43c09e
author nkeynes
date Fri Jun 26 05:47:04 2009 +0000 (14 years ago)
permissions -rw-r--r--
last change Refactor path operations into lxpaths.[ch]
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@1024
    23
#include <glib/gmem.h>
nkeynes@1024
    24
#include <glib/gstrfuncs.h>
nkeynes@1024
    25
#include "plugin.h"
nkeynes@1041
    26
#include "lxpaths.h"
nkeynes@1024
    27
nkeynes@1024
    28
#ifdef APPLE_BUILD
nkeynes@1024
    29
#define SOEXT ".dylib"
nkeynes@1024
    30
#else
nkeynes@1024
    31
#define SOEXT ".so"
nkeynes@1024
    32
#endif
nkeynes@1024
    33
nkeynes@1027
    34
/** Dummy plugin used as a plugin directory marker */
nkeynes@1027
    35
#define DUMMY_PLUGIN ("lxdream_dummy" SOEXT) 
nkeynes@1024
    36
nkeynes@1027
    37
const char *plugin_type_string[] = { "undefined", "audio driver", "input driver" };
nkeynes@1027
    38
nkeynes@1027
    39
int main(int argc, char *argv[]);
nkeynes@1027
    40
static const char *exec_path = NULL;
nkeynes@1027
    41
nkeynes@1027
    42
/**
nkeynes@1027
    43
 * Return the full path to the main binary
nkeynes@1027
    44
 */
nkeynes@1027
    45
static const char *get_exec_path()
nkeynes@1027
    46
{
nkeynes@1027
    47
    if( exec_path == NULL ) {
nkeynes@1027
    48
        Dl_info dli;
nkeynes@1027
    49
nkeynes@1027
    50
        /* Use dladdr for this, since it should be available for any platform
nkeynes@1027
    51
         * that we can support plugins on at all.
nkeynes@1027
    52
         */
nkeynes@1027
    53
        if( dladdr( main, &dli) ) {
nkeynes@1027
    54
            gchar *path = g_strdup( dli.dli_fname );
nkeynes@1027
    55
            char *i = strrchr( path, '/' );
nkeynes@1027
    56
            if( i > path ) {
nkeynes@1027
    57
                *i = '\0';
nkeynes@1027
    58
                exec_path = path;
nkeynes@1027
    59
            } else {
nkeynes@1027
    60
                g_free(path);
nkeynes@1027
    61
            }
nkeynes@1027
    62
        }
nkeynes@1027
    63
    }
nkeynes@1027
    64
    return exec_path;
nkeynes@1027
    65
}
nkeynes@1027
    66
    
nkeynes@1027
    67
static gboolean plugin_load( const gchar *plugin_path )
nkeynes@1024
    68
{
nkeynes@1024
    69
    void *so = dlopen(plugin_path, RTLD_NOW|RTLD_LOCAL);
nkeynes@1024
    70
    if( so == NULL ) {
nkeynes@1024
    71
        WARN("Failed to load plugin '%s': %s", plugin_path, dlerror());
nkeynes@1024
    72
        return FALSE;
nkeynes@1024
    73
    }
nkeynes@1024
    74
    
nkeynes@1024
    75
    struct plugin_struct *plugin = (struct plugin_struct *)dlsym(so,"lxdream_plugin_entry");
nkeynes@1024
    76
    if( plugin == NULL ) {
nkeynes@1024
    77
        WARN("Failed to load plugin: '%s': Not an lxdream plugin", plugin_path);
nkeynes@1024
    78
        dlclose(so);
nkeynes@1024
    79
        return FALSE;
nkeynes@1024
    80
    }
nkeynes@1024
    81
nkeynes@1024
    82
    if( strcmp(lxdream_short_version, plugin->version) != 0 ) {
nkeynes@1024
    83
        WARN("Failed to load plugin: '%s': Incompatible version (%s)", plugin_path, plugin->version);
nkeynes@1024
    84
        dlclose(so);
nkeynes@1024
    85
        return FALSE;
nkeynes@1024
    86
    }
nkeynes@1024
    87
nkeynes@1027
    88
    if( plugin->type == PLUGIN_NONE ) {
nkeynes@1027
    89
        /* 'dummy' plugin - we don't actually want to load it */
nkeynes@1027
    90
        dlclose(so);
nkeynes@1027
    91
        return FALSE;
nkeynes@1027
    92
    }
nkeynes@1027
    93
    
nkeynes@1024
    94
    if( plugin->type < PLUGIN_MIN_TYPE || plugin->type > PLUGIN_MAX_TYPE ) {
nkeynes@1024
    95
        WARN("Failed to load plugin: '%s': Unrecognized plugin type (%d)", plugin_path, plugin->type );
nkeynes@1024
    96
        dlclose(so);
nkeynes@1024
    97
        return FALSE;
nkeynes@1024
    98
    }
nkeynes@1024
    99
nkeynes@1024
   100
    if( plugin->register_plugin() == FALSE ) {
nkeynes@1024
   101
        WARN("Failed to load plugin: '%s': Initialization failed", plugin_path);
nkeynes@1024
   102
        dlclose(so);
nkeynes@1024
   103
        return FALSE;
nkeynes@1024
   104
    }
nkeynes@1027
   105
    INFO("Loaded %s '%s'", plugin_type_string[plugin->type], plugin->name);
nkeynes@1024
   106
    return TRUE;
nkeynes@1024
   107
}
nkeynes@1024
   108
nkeynes@1027
   109
static gboolean has_plugins( const gchar *path )
nkeynes@1027
   110
{
nkeynes@1027
   111
    struct stat st;
nkeynes@1027
   112
    
nkeynes@1027
   113
    gchar *dummy_name = g_strdup_printf( "%s/%s", path, DUMMY_PLUGIN );
nkeynes@1027
   114
    if( stat( dummy_name, &st ) == 0 ) {
nkeynes@1027
   115
        return TRUE;
nkeynes@1027
   116
    } else {
nkeynes@1027
   117
        return FALSE;
nkeynes@1027
   118
    }
nkeynes@1027
   119
}
nkeynes@1027
   120
nkeynes@1024
   121
/**
nkeynes@1024
   122
 * Scan the plugin dir and load all valid plugins.
nkeynes@1024
   123
 */
nkeynes@1027
   124
static int plugin_load_all( const gchar *plugin_dir )
nkeynes@1024
   125
{
nkeynes@1024
   126
    int plugin_count;
nkeynes@1024
   127
    struct dirent *ent;
nkeynes@1027
   128
    
nkeynes@1024
   129
    DIR *dir = opendir(plugin_dir);
nkeynes@1024
   130
    if( dir == NULL ) {
nkeynes@1024
   131
        WARN( "Unable to open plugin directory '%s'", plugin_dir );
nkeynes@1024
   132
        return 0;
nkeynes@1024
   133
    }
nkeynes@1024
   134
    
nkeynes@1024
   135
    while( (ent = readdir(dir)) != NULL ) {
nkeynes@1024
   136
        const char *ext = strrchr(ent->d_name, '.');
nkeynes@1024
   137
        if( ext != NULL && strcasecmp(SOEXT,ext) == 0 ) {
nkeynes@1024
   138
            char *libname = g_strdup_printf( "%s/%s", plugin_dir,ent->d_name );
nkeynes@1024
   139
            if( plugin_load( libname ) ) {
nkeynes@1024
   140
                plugin_count++;
nkeynes@1024
   141
            }
nkeynes@1024
   142
            g_free(libname);
nkeynes@1024
   143
        }
nkeynes@1024
   144
    }
nkeynes@1024
   145
    return plugin_count;
nkeynes@1024
   146
}
nkeynes@1027
   147
nkeynes@1027
   148
int plugin_init()
nkeynes@1027
   149
{
nkeynes@1027
   150
    const char *path = get_exec_path();
nkeynes@1027
   151
    if( path == NULL || !has_plugins(path) ) {
nkeynes@1027
   152
        path = get_plugin_path();
nkeynes@1027
   153
    }
nkeynes@1027
   154
    
nkeynes@1027
   155
    INFO( "Plugin directory: %s", path );
nkeynes@1027
   156
    return plugin_load_all( path );
nkeynes@1027
   157
}
.