lib/util: consolidate module loading into common code
[amitay/samba.git] / lib / util / modules.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Jelmer Vernooij 2002-2003,2005-2007
5    Copyright (C) Stefan (metze) Metzmacher 2003
6    Copyright (C) Andrew Bartlett 2011
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "dynconfig/dynconfig.h"
24 #include "lib/util/samba_modules.h"
25 #include "system/filesys.h"
26 #include "system/dir.h"
27
28 /**
29  * Obtain the init function from a shared library file
30  */
31 init_module_fn load_module(TALLOC_CTX *mem_ctx, const char *path)
32 {
33         void *handle;
34         void *init_fn;
35
36         handle = dlopen(path, RTLD_NOW);
37         if (handle == NULL) {
38                 DEBUG(0, ("Unable to open %s: %s\n", path, dlerror()));
39                 return NULL;
40         }
41
42         init_fn = dlsym(handle, SAMBA_INIT_MODULE);
43
44         if (init_fn == NULL) {
45                 DEBUG(0, ("Unable to find %s() in %s: %s\n",
46                           SAMBA_INIT_MODULE, path, dlerror()));
47                 DEBUG(1, ("Loading module '%s' failed\n", path));
48                 dlclose(handle);
49                 return NULL;
50         }
51
52         return (init_module_fn)init_fn;
53 }
54
55 /**
56  * Obtain list of init functions from the modules in the specified
57  * directory
58  */
59 init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path)
60 {
61         DIR *dir;
62         struct dirent *entry;
63         char *filename;
64         int success = 0;
65         init_module_fn *ret = talloc_array(mem_ctx, init_module_fn, 2);
66
67         ret[0] = NULL;
68
69         dir = opendir(path);
70         if (dir == NULL) {
71                 talloc_free(ret);
72                 return NULL;
73         }
74
75         while((entry = readdir(dir))) {
76                 if (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name))
77                         continue;
78
79                 filename = talloc_asprintf(mem_ctx, "%s/%s", path, entry->d_name);
80
81                 ret[success] = load_module(mem_ctx, filename);
82                 if (ret[success]) {
83                         ret = talloc_realloc(mem_ctx, ret, init_module_fn, success+2);
84                         success++;
85                         ret[success] = NULL;
86                 }
87
88                 talloc_free(filename);
89         }
90
91         closedir(dir);
92
93         return ret;
94 }
95
96 /**
97  * Run the specified init functions.
98  *
99  * @return true if all functions ran successfully, false otherwise
100  */
101 bool run_init_functions(init_module_fn *fns)
102 {
103         int i;
104         bool ret = true;
105
106         if (fns == NULL)
107                 return true;
108
109         for (i = 0; fns[i]; i++) { ret &= (bool)NT_STATUS_IS_OK(fns[i]()); }
110
111         return ret;
112 }
113
114 /**
115  * Load the initialization functions from DSO files for a specific subsystem.
116  *
117  * Will return an array of function pointers to initialization functions
118  */
119
120 init_module_fn *load_samba_modules(TALLOC_CTX *mem_ctx, const char *subsystem)
121 {
122         char *path = modules_path(mem_ctx, subsystem);
123         init_module_fn *ret;
124
125         ret = load_modules(mem_ctx, path);
126
127         talloc_free(path);
128
129         return ret;
130 }
131
132
133 /* Load a dynamic module.  Only log a level 0 error if we are not checking
134    for the existence of a module (probling). */
135
136 static NTSTATUS do_smb_load_module(const char *module_name, bool is_probe)
137 {
138         void *handle;
139         init_module_function *init;
140         NTSTATUS status;
141         const char *error;
142
143         /* Always try to use LAZY symbol resolving; if the plugin has
144          * backwards compatibility, there might be symbols in the
145          * plugin referencing to old (removed) functions
146          */
147         handle = dlopen(module_name, RTLD_LAZY);
148
149         /* This call should reset any possible non-fatal errors that
150            occured since last call to dl* functions */
151         error = dlerror();
152
153         if(!handle) {
154                 int level = is_probe ? 3 : 0;
155                 DEBUG(level, ("Error loading module '%s': %s\n", module_name, error ? error : ""));
156                 return NT_STATUS_UNSUCCESSFUL;
157         }
158
159         init = (init_module_function *)dlsym(handle, "init_samba_module");
160
161         /* we must check dlerror() to determine if it worked, because
162            dlsym() can validly return NULL */
163         error = dlerror();
164         if (error) {
165                 DEBUG(0, ("Error trying to resolve symbol 'init_samba_module' "
166                           "in %s: %s\n", module_name, error));
167                 dlclose(handle);
168                 return NT_STATUS_UNSUCCESSFUL;
169         }
170
171         DEBUG(2, ("Module '%s' loaded\n", module_name));
172
173         status = init();
174         if (!NT_STATUS_IS_OK(status)) {
175                 DEBUG(0, ("Module '%s' initialization failed: %s\n",
176                             module_name, get_friendly_nt_error_msg(status)));
177                 dlclose(handle);
178         }
179
180         return status;
181 }
182
183 NTSTATUS smb_load_module(const char *module_name)
184 {
185         return do_smb_load_module(module_name, false);
186 }
187
188 /* Load all modules in list and return number of
189  * modules that has been successfully loaded */
190 int smb_load_modules(const char **modules)
191 {
192         int i;
193         int success = 0;
194
195         for(i = 0; modules[i]; i++){
196                 if(NT_STATUS_IS_OK(smb_load_module(modules[i]))) {
197                         success++;
198                 }
199         }
200
201         DEBUG(2, ("%d modules successfully loaded\n", success));
202
203         return success;
204 }
205
206 NTSTATUS smb_probe_module(const char *subsystem, const char *module)
207 {
208         char *full_path = NULL;
209         TALLOC_CTX *ctx = talloc_stackframe();
210         NTSTATUS status;
211
212         /* Check for absolute path */
213
214         /* if we make any 'samba multibyte string'
215            calls here, we break
216            for loading string modules */
217
218         DEBUG(5, ("Probing module '%s'\n", module));
219
220         if (module[0] == '/') {
221                 status = do_smb_load_module(module, true);
222                 TALLOC_FREE(ctx);
223                 return status;
224         }
225
226         full_path = talloc_asprintf(ctx,
227                                     "%s/%s.%s",
228                                     modules_path(ctx, subsystem),
229                                     module,
230                                     shlib_ext());
231         if (!full_path) {
232                 TALLOC_FREE(ctx);
233                 return NT_STATUS_NO_MEMORY;
234         }
235
236         DEBUG(5, ("Probing module '%s': Trying to load from %s\n",
237                 module, full_path));
238
239         status = do_smb_load_module(full_path, true);
240
241         TALLOC_FREE(ctx);
242         return status;
243 }