e469b1da422102450abcea78f7af48f94bf0b5e1
[tprouty/samba.git] / source / lib / module.c
1 /* 
2    Unix SMB/CIFS implementation.
3    module loading system
4
5    Copyright (C) Jelmer Vernooij 2002-2003
6    Copyright (C) Stefan (metze) Metzmacher 2003
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    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 #ifdef HAVE_DLOPEN
26
27 /* Load a dynamic module.  Only log a level 0 error if we are not checking 
28    for the existence of a module (probling). */
29
30 static NTSTATUS do_smb_load_module(const char *module_name, BOOL is_probe)
31 {
32         void *handle;
33         init_module_function *init;
34         NTSTATUS status;
35         const char *error;
36
37         /* Always try to use LAZY symbol resolving; if the plugin has 
38          * backwards compatibility, there might be symbols in the 
39          * plugin referencing to old (removed) functions
40          */
41         handle = sys_dlopen(module_name, RTLD_LAZY);
42
43         /* This call should reset any possible non-fatal errors that 
44            occured since last call to dl* functions */
45         error = sys_dlerror();
46
47         if(!handle) {
48                 int level = is_probe ? 3 : 0;
49                 DEBUG(level, ("Error loading module '%s': %s\n", module_name, error ? error : ""));
50                 return NT_STATUS_UNSUCCESSFUL;
51         }
52
53         init = (init_module_function *)sys_dlsym(handle, "init_module");
54
55         /* we must check sys_dlerror() to determine if it worked, because
56            sys_dlsym() can validly return NULL */
57         error = sys_dlerror();
58         if (error) {
59                 DEBUG(0, ("Error trying to resolve symbol 'init_module' in %s: %s\n", 
60                           module_name, error));
61                 return NT_STATUS_UNSUCCESSFUL;
62         }
63
64         status = init();
65
66         DEBUG(2, ("Module '%s' loaded\n", module_name));
67
68         return status;
69 }
70
71 NTSTATUS smb_load_module(const char *module_name)
72 {
73         return do_smb_load_module(module_name, False);
74 }
75
76 /* Load all modules in list and return number of 
77  * modules that has been successfully loaded */
78 int smb_load_modules(const char **modules)
79 {
80         int i;
81         int success = 0;
82
83         for(i = 0; modules[i]; i++){
84                 if(NT_STATUS_IS_OK(smb_load_module(modules[i]))) {
85                         success++;
86                 }
87         }
88
89         DEBUG(2, ("%d modules successfully loaded\n", success));
90
91         return success;
92 }
93
94 NTSTATUS smb_probe_module(const char *subsystem, const char *module)
95 {
96         pstring full_path;
97         
98         /* Check for absolute path */
99
100         /* if we make any 'samba multibyte string' 
101            calls here, we break 
102            for loading string modules */
103
104         DEBUG(5, ("Probing module '%s'\n", module));
105
106         if (module[0] == '/')
107                 return do_smb_load_module(module, True);
108         
109         pstrcpy(full_path, lib_path(subsystem));
110         pstrcat(full_path, "/");
111         pstrcat(full_path, module);
112         pstrcat(full_path, ".");
113         pstrcat(full_path, shlib_ext());
114
115         DEBUG(5, ("Probing module '%s': Trying to load from %s\n", module, full_path));
116         
117         return do_smb_load_module(full_path, True);
118 }
119
120 #else /* HAVE_DLOPEN */
121
122 NTSTATUS smb_load_module(const char *module_name)
123 {
124         DEBUG(0,("This samba executable has not been built with plugin support\n"));
125         return NT_STATUS_NOT_SUPPORTED;
126 }
127
128 int smb_load_modules(const char **modules)
129 {
130         DEBUG(0,("This samba executable has not been built with plugin support\n"));
131         return -1;
132 }
133
134 NTSTATUS smb_probe_module(const char *subsystem, const char *module)
135 {
136         DEBUG(0,("This samba executable has not been built with plugin support, not probing\n")); 
137         return NT_STATUS_NOT_SUPPORTED;
138 }
139
140 #endif /* HAVE_DLOPEN */
141
142 void init_modules(void)
143 {
144         /* FIXME: This can cause undefined symbol errors :
145          *  smb_register_vfs() isn't available in nmbd, for example */
146         if(lp_preload_modules()) 
147                 smb_load_modules(lp_preload_modules());
148 }
149
150
151 /***************************************************************************
152  * This Function registers a idle event
153  *
154  * the registered funtions are run periodically
155  * and maybe shutdown idle connections (e.g. to an LDAP server)
156  ***************************************************************************/
157 static smb_event_id_t smb_idle_event_id = 1;
158
159 struct smb_idle_list_ent {
160         struct smb_idle_list_ent *prev,*next;
161         smb_event_id_t id;
162         smb_idle_event_fn *fn;
163         void *data;
164         time_t interval;
165         time_t lastrun;
166 };
167
168 static struct smb_idle_list_ent *smb_idle_event_list = NULL;
169
170 smb_event_id_t smb_register_idle_event(smb_idle_event_fn *fn, void *data, time_t interval)
171 {
172         struct smb_idle_list_ent *event;
173
174         if (!fn) {      
175                 return SMB_EVENT_ID_INVALID;
176         }
177
178         event = (struct smb_idle_list_ent *)malloc(sizeof(struct smb_idle_list_ent));
179         if (!event) {
180                 DEBUG(0,("malloc() failed!\n"));
181                 return SMB_EVENT_ID_INVALID;
182         }
183         event->fn = fn;
184         event->data = data;
185         event->interval = interval;
186         event->lastrun = 0;
187         event->id = smb_idle_event_id++;
188
189         DLIST_ADD(smb_idle_event_list,event);
190
191         return event->id;
192 }
193
194 BOOL smb_unregister_idle_event(smb_event_id_t id)
195 {
196         struct smb_idle_list_ent *event = smb_idle_event_list;
197         
198         while(event) {
199                 if (event->id == id) {
200                         DLIST_REMOVE(smb_idle_event_list,event);
201                         SAFE_FREE(event);
202                         return True;
203                 }
204                 event = event->next;
205         }
206         
207         return False;
208 }
209
210 void smb_run_idle_events(time_t now)
211 {
212         struct smb_idle_list_ent *event = smb_idle_event_list;
213
214         while (event) {
215                 struct smb_idle_list_ent *next = event->next;
216                 time_t interval;
217
218                 if (event->interval <= 0) {
219                         interval = SMB_IDLE_EVENT_DEFAULT_INTERVAL;
220                 } else if (event->interval >= SMB_IDLE_EVENT_MIN_INTERVAL) {
221                         interval = event->interval;
222                 } else {
223                         interval = SMB_IDLE_EVENT_MIN_INTERVAL;
224                 }
225                 if (now >(event->lastrun+interval)) {
226                         event->lastrun = now;
227                         event->fn(&event->data,&event->interval,now);
228                 }
229                 event = next;
230         }
231
232         return;
233 }
234
235 /***************************************************************************
236  * This Function registers a exit event
237  *
238  * the registered functions are run on exit()
239  * and maybe shutdown idle connections (e.g. to an LDAP server)
240  ***************************************************************************/
241
242 struct smb_exit_list_ent {
243         struct smb_exit_list_ent *prev,*next;
244         smb_event_id_t id;
245         smb_exit_event_fn *fn;
246         void *data;
247 };
248
249 static struct smb_exit_list_ent *smb_exit_event_list = NULL;
250
251 smb_event_id_t smb_register_exit_event(smb_exit_event_fn *fn, void *data)
252 {
253         struct smb_exit_list_ent *event;
254         static smb_event_id_t smb_exit_event_id = 1;
255
256         if (!fn) {      
257                 return SMB_EVENT_ID_INVALID;
258         }
259
260         event = (struct smb_exit_list_ent *)malloc(sizeof(struct smb_exit_list_ent));
261         if (!event) {
262                 DEBUG(0,("malloc() failed!\n"));
263                 return SMB_EVENT_ID_INVALID;
264         }
265         event->fn = fn;
266         event->data = data;
267         event->id = smb_exit_event_id++;
268
269         DLIST_ADD(smb_exit_event_list,event);
270
271         return event->id;
272 }
273
274 BOOL smb_unregister_exit_event(smb_event_id_t id)
275 {
276         struct smb_exit_list_ent *event = smb_exit_event_list;
277         
278         while(event) {
279                 if (event->id == id) {
280                         DLIST_REMOVE(smb_exit_event_list,event);
281                         SAFE_FREE(event);
282                         return True;
283                 }
284                 event = event->next;
285         }
286         
287         return False;
288 }
289
290 void smb_run_exit_events(void)
291 {
292         struct smb_exit_list_ent *event = smb_exit_event_list;
293         struct smb_exit_list_ent *tmp = NULL;
294
295         while (event) {
296                 event->fn(&event->data);
297                 tmp = event;
298                 event = event->next;
299                 /* exit event should only run one time :-)*/
300                 SAFE_FREE(tmp);
301         }
302
303         /* the list is empty now...*/
304         smb_exit_event_list = NULL;
305
306         return;
307 }