]> git.sur5r.net Git - openldap/blob - servers/slapd/module.c
c460736c153a8c90bc1c1ec56790f5927897124e
[openldap] / servers / slapd / module.c
1 /* $OpenLDAP$ */
2 #include "portable.h"
3 #include <stdio.h>
4 #include "slap.h"
5
6 #ifdef SLAPD_MODULES
7
8 #include <ltdl.h>
9
10 int load_null (const void *module, const char *file_name);
11 int load_extension (const void *module, const char *file_name);
12
13 struct module_regtable_t {
14         char *type;
15         int (*proc)(const void *module, const char *file_name);
16 } module_regtable[] = {
17                 { "null", load_null },
18 #ifdef SLAPD_EXTERNAL_EXTENSIONS
19                 { "extension", load_extension },
20 #endif
21                 { NULL, NULL }
22 };
23
24 typedef struct module_loaded_t {
25         struct module_loaded_t *next;
26         lt_dlhandle *lib;
27 } module_loaded_t;
28
29 module_loaded_t *module_list = NULL;
30
31 int module_unload (module_loaded_t *module);
32
33 int module_init (void)
34 {
35         if (lt_dlinit()) {
36                 const char *error = lt_dlerror();
37                 Debug(LDAP_DEBUG_ANY, "lt_dlinit failed: %s\n", error, 0, 0);
38                 return -1;
39         }
40         return 0;
41 }
42
43 int module_kill (void)
44 {
45         /* unload all modules before shutdown */
46         while (module_list != NULL) {
47                 module_unload(module_list);
48         }
49
50         if (lt_dlexit()) {
51                 const char *error = lt_dlerror();
52                 Debug(LDAP_DEBUG_ANY, "lt_dlexit failed: %s\n", error, 0, 0);
53                 return -1;
54         }
55         return 0;
56 }
57
58 int module_load(const char* file_name, int argc, char *argv[])
59 {
60         module_loaded_t *module = NULL;
61         const char *error;
62         int rc;
63         int (*initialize) LDAP_P((int argc, char *argv[]));
64
65         module = (module_loaded_t *)ch_calloc(1, sizeof(module_loaded_t));
66         if (module == NULL) {
67                 Debug(LDAP_DEBUG_ANY, "module_load failed: (%s) out of memory\n", file_name,
68                         0, 0);
69                 return -1;
70         }
71
72         /*
73          * The result of lt_dlerror(), when called, must be cached prior
74          * to calling Debug. This is because Debug is a macro that expands
75          * into multiple function calls.
76          */
77         if ((module->lib = lt_dlopen(file_name)) == NULL) {
78                 error = lt_dlerror();
79                 Debug(LDAP_DEBUG_ANY, "lt_dlopen failed: (%s) %s\n", file_name,
80                         error, 0);
81                 ch_free(module);
82                 return -1;
83         }
84
85         Debug(LDAP_DEBUG_CONFIG, "loaded module %s\n", file_name, 0, 0);
86    
87         if ((initialize = lt_dlsym(module->lib, "init_module")) == NULL) {
88                 Debug(LDAP_DEBUG_CONFIG, "module %s: no init_module() function found\n",
89                         file_name, 0, 0);
90                 lt_dlclose(module->lib);
91                 ch_free(module);
92                 return -1;
93         }
94
95         /* The imported init_module() routine passes back the type of
96          * module (i.e., which part of slapd it should be hooked into)
97          * or -1 for error.  If it passes back 0, then you get the 
98          * old behavior (i.e., the library is loaded and not hooked
99          * into anything).
100          *
101          * It might be better if the conf file could specify the type
102          * of module.  That way, a single module could support multiple
103          * type of hooks. This could be done by using something like:
104          *
105          *    moduleload extension /usr/local/openldap/whatever.so
106          *
107          * then we'd search through module_regtable for a matching
108          * module type, and hook in there.
109          */
110         rc = initialize(argc, argv);
111         if (rc == -1) {
112                 Debug(LDAP_DEBUG_CONFIG, "module %s: init_module() failed\n",
113                         file_name, 0, 0);
114                 lt_dlclose(module->lib);
115                 ch_free(module);
116                 return rc;
117         }
118
119         if (rc >= (sizeof(module_regtable) / sizeof(struct module_regtable_t))
120                 || module_regtable[rc].proc == NULL)
121         {
122                 Debug(LDAP_DEBUG_CONFIG, "module %s: unknown registration type (%d)\n",
123                         file_name, rc, 0);
124                 module_unload(module);
125                 return -1;
126         }
127
128         rc = (module_regtable[rc].proc)(module, file_name);
129         if (rc != 0) {
130                 Debug(LDAP_DEBUG_CONFIG, "module %s: %s module could not be registered\n",
131                         file_name, module_regtable[rc].type, 0);
132                 module_unload(module);
133                 return rc;
134         }
135
136         module->next = module_list;
137         module_list = module;
138
139         Debug(LDAP_DEBUG_CONFIG, "module %s: %s module registered\n",
140                 file_name, module_regtable[rc].type, 0);
141         return 0;
142 }
143
144 int module_path(const char *path)
145 {
146         return lt_dlsetsearchpath( path );
147 }
148
149 void *module_resolve (const void *module, const char *name)
150 {
151         if (module == NULL || name == NULL)
152                 return(NULL);
153         return(lt_dlsym(((module_loaded_t *)module)->lib, name));
154 }
155
156 int module_unload (module_loaded_t *module)
157 {
158         module_loaded_t *mod;
159         int (*terminate) LDAP_P((void));
160
161         if (module != NULL) {
162                 /* remove module from tracking list */
163                 if (module_list == module) {
164                         module_list = module->next;
165                 } else {
166                         for (mod = module_list; mod; mod = mod->next) {
167                                 if (mod->next == module) {
168                                         mod->next = module->next;
169                                         break;
170                                 }
171                         }
172                 }
173
174                 /* call module's terminate routine, if present */
175                 if (terminate = lt_dlsym(module->lib, "term_module")) {
176                         terminate();
177                 }
178
179                 /* close the library and free the memory */
180                 lt_dlclose(module->lib);
181                 ch_free(module);
182         }
183         return 0;
184 }
185
186 int load_null (const void *module, const char *file_name)
187 {
188         return 0;
189 }
190
191 #endif /* SLAPD_MODULES */
192