80360e4e728f68140e50063d3f1ce735527c4098
[jelmer/samba4-debian.git] / source / 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 #include "system/dir.h"
24 #include "system/filesys.h"
25 #include "dlinklist.h"
26
27 #ifdef HAVE_DLOPEN
28
29 /* Load module (or directory with modules) recursively. 
30  * Includes running the init_module() function */
31 NTSTATUS smb_load_module(const char *module_name)
32 {
33         void *handle;
34         init_module_function init;
35         NTSTATUS status;
36         const char *error;
37         struct stat st;
38         DIR *dir;
39         struct dirent *dirent;
40
41         if(stat(module_name, &st) < 0) {
42                 DEBUG(0, ("Can't stat module '%s'\n", module_name));
43                 return NT_STATUS_UNSUCCESSFUL;
44         }
45
46         /* If the argument is a directory, recursively load all files / 
47          * directories in it */
48
49         /* How about symlinks pointing to themselves - wouldn't we rather 
50          * want to use wildcards here? */
51         if(S_ISDIR(st.st_mode)) {
52                 dir = opendir(module_name);
53                 while ((dirent = readdir(dir))) {
54                         smb_load_module(dirent->d_name);
55                 }
56         }
57
58         /* Always try to use LAZY symbol resolving; if the plugin has 
59          * backwards compatibility, there might be symbols in the 
60          * plugin referencing to old (removed) functions
61          */
62         handle = sys_dlopen(module_name, RTLD_LAZY);
63
64         if(!handle) {
65                 DEBUG(0, ("Error loading module '%s': %s\n", module_name, sys_dlerror()));
66                 return NT_STATUS_UNSUCCESSFUL;
67         }
68
69         init = (init_module_function)sys_dlsym(handle, "init_module");
70
71         /* we must check sys_dlerror() to determine if it worked, because
72            sys_dlsym() can validly return NULL */
73         error = sys_dlerror();
74         if (error) {
75                 DEBUG(0, ("Error trying to resolve symbol 'init_module' in %s: %s\n", module_name, error));
76                 return NT_STATUS_UNSUCCESSFUL;
77         }
78
79         status = init();
80
81         DEBUG(2, ("Module '%s' loaded\n", module_name));
82
83         return status;
84 }
85
86 /* Load all modules in list and return number of 
87  * modules that has been successfully loaded */
88 int smb_load_modules(const char **modules)
89 {
90         int i;
91         int success = 0;
92
93         for(i = 0; modules[i]; i++){
94                 if(NT_STATUS_IS_OK(smb_load_module(modules[i]))) {
95                         success++;
96                 }
97         }
98
99         DEBUG(2, ("%d modules successfully loaded\n", success));
100
101         return success;
102 }
103
104 #else /* HAVE_DLOPEN */
105
106 NTSTATUS smb_load_module(const char *module_name)
107 {
108         DEBUG(0,("This samba executable has not been built with plugin support\n"));
109         return NT_STATUS_NOT_SUPPORTED;
110 }
111
112 int smb_load_modules(const char **modules)
113 {
114         DEBUG(0,("This samba executable has not been built with plugin support\n"));
115         return -1;
116 }
117
118 #endif /* HAVE_DLOPEN */
119
120 void init_modules(void)
121 {
122         if(lp_preload_modules()) 
123                 smb_load_modules(lp_preload_modules());
124 }
125
126 struct subsystem {
127         char *name;
128         register_backend_function callback;
129         struct subsystem *prev, *next;
130 };
131
132 static struct subsystem *subsystems = NULL;
133
134 NTSTATUS register_subsystem(const char *name, register_backend_function callback) 
135 {
136         struct subsystem *s;
137         struct subsystem *t = subsystems;
138
139         while(t) {
140                 if(!strcmp(name, t->name)) {
141                         /* its already registered! */
142                         DEBUG(0,("Subsystem '%s' already registered\n", name));
143                         return NT_STATUS_OBJECT_NAME_COLLISION;
144                 }
145                 t = t->next;
146         }
147
148         s = smb_xmalloc(sizeof(struct subsystem));
149
150         s->name = smb_xstrdup(name);
151         s->callback = callback;
152         s->prev = s->next = NULL;
153
154         DLIST_ADD(subsystems, s);
155
156         return NT_STATUS_OK;
157 }
158
159 NTSTATUS register_backend(const char *subsystem, const void *args)
160 {
161         /* Find the specified subsystem */
162         struct subsystem *s = subsystems;
163
164         while(s) {
165                 if(!strcmp(subsystem, s->name)) return s->callback(args);
166                 s = s->next;
167         }
168         
169         DEBUG(0, ("Unable to register backend for subsystem '%s'\n", subsystem));
170
171         return NT_STATUS_NOT_IMPLEMENTED;
172 }