67fb830e6f62961556346ca1d17cf3e7623800ac
[samba.git] / source4 / lib / module.c
1 /* 
2    Unix SMB/CIFS implementation.
3    module loading system
4
5    Copyright (C) Jelmer Vernooij 2002-2004
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 #ifdef HAVE_DLOPEN
25
26 /* Load module (or directory with modules) recursively. 
27  * Includes running the init_module() function */
28 NTSTATUS smb_load_module(const char *module_name)
29 {
30         void *handle;
31         init_module_function init;
32         NTSTATUS status;
33         const char *error;
34         struct stat st;
35         DIR *dir;
36         struct dirent *dirent;
37
38         if(stat(module_name, &st) < 0) {
39                 DEBUG(0, ("Can't stat module '%s'\n", module_name));
40                 return NT_STATUS_UNSUCCESSFUL;
41         }
42
43         /* If the argument is a directory, recursively load all files / 
44          * directories in it */
45
46         /* How about symlinks pointing to themselves - wouldn't we rather 
47          * want to use wildcards here? */
48         if(S_ISDIR(st.st_mode)) {
49                 dir = opendir(module_name);
50                 while ((dirent = readdir(dir))) {
51                         smb_load_module(dirent->d_name);
52                 }
53         }
54
55         /* Always try to use LAZY symbol resolving; if the plugin has 
56          * backwards compatibility, there might be symbols in the 
57          * plugin referencing to old (removed) functions
58          */
59         handle = sys_dlopen(module_name, RTLD_LAZY);
60
61         if(!handle) {
62                 DEBUG(0, ("Error loading module '%s': %s\n", module_name, sys_dlerror()));
63                 return NT_STATUS_UNSUCCESSFUL;
64         }
65
66         init = (init_module_function)sys_dlsym(handle, "init_module");
67
68         /* we must check sys_dlerror() to determine if it worked, because
69            sys_dlsym() can validly return NULL */
70         error = sys_dlerror();
71         if (error) {
72                 DEBUG(0, ("Error trying to resolve symbol 'init_module' in %s: %s\n", module_name, error));
73                 return NT_STATUS_UNSUCCESSFUL;
74         }
75
76         status = init();
77
78         DEBUG(2, ("Module '%s' loaded\n", module_name));
79
80         return status;
81 }
82
83 /* Load all modules in list and return number of 
84  * modules that has been successfully loaded */
85 int smb_load_modules(const char **modules)
86 {
87         int i;
88         int success = 0;
89
90         for(i = 0; modules[i]; i++){
91                 if(NT_STATUS_IS_OK(smb_load_module(modules[i]))) {
92                         success++;
93                 }
94         }
95
96         DEBUG(2, ("%d modules successfully loaded\n", success));
97
98         return success;
99 }
100
101 #else /* HAVE_DLOPEN */
102
103 NTSTATUS smb_load_module(const char *module_name)
104 {
105         DEBUG(0,("This samba executable has not been built with plugin support\n"));
106         return NT_STATUS_NOT_SUPPORTED;
107 }
108
109 int smb_load_modules(const char **modules)
110 {
111         DEBUG(0,("This samba executable has not been built with plugin support\n"));
112         return -1;
113 }
114
115 #endif /* HAVE_DLOPEN */
116
117 void init_modules(void)
118 {
119         if(lp_preload_modules()) 
120                 smb_load_modules(lp_preload_modules());
121 }
122
123 struct subsystem {
124         char *name;
125         register_backend_function callback;
126         struct subsystem *prev, *next;
127 };
128
129 static struct subsystem *subsystems = NULL;
130
131 NTSTATUS register_subsystem(const char *name, register_backend_function callback) 
132 {
133         struct subsystem *s;
134         struct subsystem *t = subsystems;
135
136         while(t) {
137                 if(!strcmp(name, t->name)) {
138                         /* its already registered! */
139                         DEBUG(0,("Subsystem '%s' already registered\n", name));
140                         return NT_STATUS_OBJECT_NAME_COLLISION;
141                 }
142                 t = t->next;
143         }
144
145         s = smb_xmalloc(sizeof(struct subsystem));
146
147         s->name = smb_xstrdup(name);
148         s->callback = callback;
149         s->prev = s->next = NULL;
150
151         DLIST_ADD(subsystems, s);
152
153         return NT_STATUS_OK;
154 }
155
156 NTSTATUS register_backend(const char *subsystem, const void *args)
157 {
158         /* Find the specified subsystem */
159         struct subsystem *s = subsystems;
160
161         while(s) {
162                 if(!strcmp(subsystem, s->name)) return s->callback(args);
163                 s = s->next;
164         }
165         
166         DEBUG(0, ("Unable to register backend for subsystem '%s'\n", subsystem));
167
168         return NT_STATUS_NOT_IMPLEMENTED;
169 }