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