ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/src/module.C
Revision: 1.1
Committed: Thu Jul 19 08:24:59 2007 UTC (16 years, 11 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Log Message:
initial import. the most important changes since Atheme are:
- fixed many memory leaks
- fixed many bugs
- converted to C++ and use more STL containers
- added a (not very enhanced yet) perl module
- greatly improved XML-RPC speed
- added a JSON-RPC module with code from json-cpp
- added a valgrind memcheck module to operserv
- added a more object oriented base64 implementation
- added a specialised unit test framework
- improved stability
- use gettimeofday() if available
- reworked adding/removing commands
- MemoServ IGNORE DEL can now remove indices

File Contents

# Content
1 /*
2 * module.C: Module management.
3 * Rights to this code are documented in doc/LICENSE.
4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */
7
8 static char const rcsid[] = "$Id";
9
10 #include "atheme.h"
11
12 #include <dlfcn.h>
13
14 static BlockHeap *module_heap;
15 list_t modules;
16
17 module_t *modtarget = NULL;
18
19 void
20 modules_init (void)
21 {
22 module_heap = BlockHeapCreate (sizeof (module_t), 256);
23
24 if (!module_heap)
25 {
26 slog (LG_ERROR, "modules_init(): block allocator failed.");
27 exit (EXIT_FAILURE);
28 }
29
30 module_load_dir (MODDIR "/modules");
31 }
32
33 /*
34 * module_load()
35 *
36 * inputs:
37 * a literal filename for a module to load.
38 *
39 * outputs:
40 * the respective module_t object of the module.
41 *
42 * side effects:
43 * a module is loaded and necessary initialization code is run.
44 */
45 module_t *
46 module_load (char *filespec)
47 {
48 node_t *n;
49 module_t *m;
50 v1_moduleheader_t *h;
51 void *handle = NULL;
52 #ifdef HAVE_DLINFO
53 struct link_map *map;
54 #endif
55
56 if ((m = module_find (filespec)))
57 {
58 slog (LG_INFO, "module_load(): module %s is already loaded [at 0x%lx]", filespec, m->address);
59 return NULL;
60 }
61
62 handle = linker_open_ext (filespec);
63
64 if (!handle)
65 {
66 char *errp = sstrdup (dlerror ());
67 slog (LG_ERROR, "module_load(): error: %s", errp);
68 if (me.connected)
69 snoop (_("MODLOAD:ERROR: loading module \2%s\2: %s"), filespec, errp);
70 free (errp);
71 return NULL;
72 }
73
74 h = (v1_moduleheader_t *) linker_getsym (handle, "_header");
75
76 if (!h)
77 return NULL;
78
79 if (h->mod != MAPI_MAGIC)
80 {
81 slog (LG_DEBUG, "module_load(): %s: Attempted to load an incompatible module. Aborting.", filespec);
82
83 if (me.connected)
84 snoop (_("MODLOAD:ERROR: Module \2%s\2 is not a valid " PACKAGE_NAME " module."), filespec);
85
86 linker_close (handle);
87 return NULL;
88 }
89
90 m = static_cast<module_t *> (BlockHeapAlloc (module_heap));
91
92 strlcpy (m->modpath, filespec, BUFSIZE);
93 m->handle = handle;
94 m->mflags = MODTYPE_STANDARD;
95 m->header = h;
96
97 #ifdef HAVE_DLINFO
98 dlinfo (handle, RTLD_DI_LINKMAP, &map);
99 if (map != NULL)
100 m->address = (void *) map->l_addr;
101 else
102 m->address = handle;
103 #else
104 /* best we can do here without dlinfo() --nenolod */
105 m->address = handle;
106 #endif
107
108 /* set the module target for module dependencies */
109 modtarget = m;
110
111 if (h->modinit)
112 h->modinit (m);
113
114 /* we won't be loading symbols outside the init code */
115 modtarget = NULL;
116
117 if (m->mflags & MODTYPE_FAIL)
118 {
119 slog (LG_ERROR, "module_load(): module %s init failed", filespec);
120 if (me.connected)
121 snoop (_("MODLOAD:ERROR: Init failed while loading module \2%s\2"), filespec);
122 module_unload (m);
123 return NULL;
124 }
125
126 n = node_create ();
127 node_add (m, n, &modules);
128
129 slog (LG_DEBUG, "module_load(): loaded %s [at 0x%lx; MAPI version %d]", h->name, m->address, h->abi_ver);
130
131 if (me.connected && !cold_start)
132 {
133 wallops (_("Module %s loaded [at 0x%lx; MAPI version %d]"), h->name, m->address, h->abi_ver);
134 snoop (_("MODLOAD: \2%s\2 [at 0x%lx; MAPI version %d]"), h->name, m->address, h->abi_ver);
135 }
136
137 return m;
138 }
139
140 /*
141 * module_load_dir()
142 *
143 * inputs:
144 * a directory containing modules to load.
145 *
146 * outputs:
147 * none
148 *
149 * side effects:
150 * qualifying modules are passed to module_load().
151 */
152 void
153 module_load_dir (char *dirspec)
154 {
155 DIR *module_dir = NULL;
156 struct dirent *ldirent = NULL;
157 char module_filename[4096];
158
159 module_dir = opendir (dirspec);
160
161 if (!module_dir)
162 {
163 slog (LG_ERROR, "module_load_dir(): %s: %s", dirspec, strerror (errno));
164 return;
165 }
166
167 while ((ldirent = readdir (module_dir)) != NULL)
168 {
169 if (!strstr (ldirent->d_name, ".so"))
170 continue;
171
172 snprintf (module_filename, sizeof (module_filename), "%s/%s", dirspec, ldirent->d_name);
173 module_load (module_filename);
174 }
175
176 closedir (module_dir);
177 }
178
179 /*
180 * module_load_dir_match()
181 *
182 * inputs:
183 * a directory containing modules to load, and a pattern to match against
184 * to determine whether or not a module qualifies for loading.
185 *
186 * outputs:
187 * none
188 *
189 * side effects:
190 * qualifying modules are passed to module_load().
191 */
192 void
193 module_load_dir_match (char *dirspec, char *pattern)
194 {
195 DIR *module_dir = NULL;
196 struct dirent *ldirent = NULL;
197 char module_filename[4096];
198
199 module_dir = opendir (dirspec);
200
201 if (!module_dir)
202 {
203 slog (LG_ERROR, "module_load_dir(): %s: %s", dirspec, strerror (errno));
204 return;
205 }
206
207 while ((ldirent = readdir (module_dir)) != NULL)
208 {
209 if (!strstr (ldirent->d_name, ".so") && match (pattern, ldirent->d_name))
210 continue;
211
212 snprintf (module_filename, sizeof (module_filename), "%s/%s", dirspec, ldirent->d_name);
213 module_load (module_filename);
214 }
215
216 closedir (module_dir);
217 }
218
219 /*
220 * module_unload()
221 *
222 * inputs:
223 * a module object to unload.
224 *
225 * outputs:
226 * none
227 *
228 * side effects:
229 * a module is unloaded and neccessary deinitalization code is run.
230 */
231 void
232 module_unload (module_t *m)
233 {
234 node_t *n, *tn;
235
236 if (!m)
237 return;
238
239 /* unload modules which depend on us */
240 LIST_FOREACH_SAFE (n, tn, m->dephost.head) module_unload ((module_t *) n->data);
241
242 /* let modules that we depend on know that we no longer exist */
243 LIST_FOREACH_SAFE (n, tn, m->deplist.head)
244 {
245 module_t *hm = (module_t *) n->data;
246 node_t *hn = node_find (m, &hm->dephost);
247
248 node_del (hn, &hm->dephost);
249 node_free (hn);
250 node_del (n, &m->deplist);
251 node_free (n);
252 }
253
254 n = node_find (m, &modules);
255 if (n != NULL)
256 {
257 slog (LG_INFO, "module_unload(): unloaded %s", m->header->name);
258 if (me.connected)
259 {
260 wallops (_("Module %s unloaded."), m->header->name);
261 snoop ("MODUNLOAD: \2%s\2", m->header->name);
262 }
263
264 if (m->header->deinit)
265 m->header->deinit ();
266 node_del (n, &modules);
267 node_free (n);
268 }
269 /* else unloaded in embryonic state */
270 linker_close (m->handle);
271 BlockHeapFree (module_heap, m);
272 }
273
274 /*
275 * module_locate_symbol()
276 *
277 * inputs:
278 * a name of a module and a symbol to look for inside it.
279 *
280 * outputs:
281 * the pointer to the module symbol, else NULL if not found.
282 *
283 * side effects:
284 * none
285 */
286 void *
287 module_locate_symbol (char *modname, char *sym)
288 {
289 module_t *m;
290 void *symptr;
291
292 if (!(m = module_find_published (modname)))
293 {
294 slog (LG_ERROR, "module_locate_symbol(): %s is not loaded.", modname);
295 return NULL;
296 }
297
298 if (modtarget != NULL && !node_find (m, &modtarget->deplist))
299 {
300 slog (LG_DEBUG, "module_locate_symbol(): %s added as a dependency for %s (symbol: %s)", m->header->name, modtarget->header->name, sym);
301 node_add (m, node_create (), &modtarget->deplist);
302 node_add (modtarget, node_create (), &m->dephost);
303 }
304
305 symptr = linker_getsym (m->handle, sym);
306
307 if (symptr == NULL)
308 slog (LG_ERROR, "module_locate_symbol(): could not find symbol %s in module %s.", sym, modname);
309 return symptr;
310 }
311
312 /*
313 * module_find()
314 *
315 * inputs:
316 * a name of a module to locate the object for.
317 *
318 * outputs:
319 * the module object if the module is located, else NULL.
320 *
321 * side effects:
322 * none
323 */
324 module_t *
325 module_find (char *name)
326 {
327 node_t *n;
328
329 LIST_FOREACH (n, modules.head)
330 {
331 module_t *m = static_cast<module_t *> (n->data);
332
333 if (!strcasecmp (m->modpath, name))
334 return m;
335 }
336
337 return NULL;
338 }
339
340 /*
341 * module_find_published()
342 *
343 * inputs:
344 * a published (in _header) name of a module to locate the object for.
345 *
346 * outputs:
347 * the module object if the module is located, else NULL.
348 *
349 * side effects:
350 * none
351 */
352 module_t *
353 module_find_published (char *name)
354 {
355 node_t *n;
356
357 LIST_FOREACH (n, modules.head)
358 {
359 module_t *m = static_cast<module_t *> (n->data);
360
361 if (!strcasecmp (m->header->name, name))
362 return m;
363 }
364
365 return NULL;
366 }
367
368 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
369 * vim:ts=8
370 * vim:sw=8
371 * vim:noexpandtab
372 */