ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/module.C
(Generate patch)

Comparing ermyth/src/module.C (file contents):
Revision 1.3 by pippijn, Sat Jul 21 13:23:22 2007 UTC vs.
Revision 1.4 by pippijn, Tue Aug 28 17:08:12 2007 UTC

1/* 1#include <svsconfig.h>
2 * module.C: Module management. 2#include <common.h>
3 * Rights to this code are documented in doc/pod/license.pod. 3#include <ermyth/module.h>
4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */
7 4
8static char const rcsid[] = "$Id: module.C,v 1.3 2007/07/21 13:23:22 pippijn Exp $"; 5modules::modules (srcinf const &si, char const * const name, bool norestart, bool (*init)(module *), void (*fini)(),
9 6 char const * const vendor, char const * const modversion)
10#include "atheme.h"
11
12#include <dlfcn.h>
13
14static BlockHeap *module_heap;
15list_t modules;
16
17module_t *modtarget = NULL;
18
19void
20modules_init (void)
21{ 7{
22 module_heap = BlockHeapCreate (sizeof (module_t), 256); 8 if (provides (name))
23 9 throw module_exception (si, "Trying to register two modules with the same name: %s", name);
24 if (!module_heap) 10 module *mod = new module (name, norestart, init, fini, vendor, modversion);
25 { 11 modlist ().push_back (mod);
26 slog (LG_ERROR, "modules_init(): block allocator failed."); 12 provides (name);
27 exit (EXIT_FAILURE);
28 }
29
30 module_load_dir (MODDIR "/modules");
31} 13}
32 14
33/* 15bool
34 * module_load() 16modules::provides (char const * const name)
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 */
45module_t *
46module_load (char *filespec)
47{ 17{
48 node_t *n; 18 if (find (name) != NULL)
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; 19 return true;
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; 20 return false;
138} 21}
139 22
140/* 23faultcode_t
141 * module_load_dir() 24modules::enable (char const * const name)
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 */
152void
153module_load_dir (char *dirspec)
154{ 25{
155 DIR *module_dir = NULL; 26 module *m = find (name);
156 struct dirent *ldirent = NULL;
157 char module_filename[4096];
158 27
159 module_dir = opendir (dirspec); 28 if (!m)
29 return fault_nosuch_target;
30
31 if (m->enabled)
32 return fault_nochange;
160 33
161 if (!module_dir) 34 m->enabled = m->init (m);
162 {
163 slog (LG_ERROR, "module_load_dir(): %s: %s", dirspec, strerror (errno));
164 return;
165 }
166 35
167 while ((ldirent = readdir (module_dir)) != NULL) 36 return m->enabled ? fault_ok : fault_failed;
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} 37}
178 38
179/* 39faultcode_t
180 * module_load_dir_match() 40modules::disable (char const * const name)
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 */
192void
193module_load_dir_match (char *dirspec, char *pattern)
194{ 41{
195 DIR *module_dir = NULL; 42 module *m = find (name);
196 struct dirent *ldirent = NULL;
197 char module_filename[4096];
198 43
199 module_dir = opendir (dirspec); 44 if (!m)
45 return fault_nosuch_target;
200 46
201 if (!module_dir) 47 if (m->norestart)
202 { 48 return fault_noprivs;
203 slog (LG_ERROR, "module_load_dir(): %s: %s", dirspec, strerror (errno));
204 return;
205 }
206 49
207 while ((ldirent = readdir (module_dir)) != NULL) 50 if (m->enabled)
208 { 51 m->fini ();
209 if (!strstr (ldirent->d_name, ".so") && match (pattern, ldirent->d_name)) 52 else
210 continue; 53 return fault_nochange;
211 54
212 snprintf (module_filename, sizeof (module_filename), "%s/%s", dirspec, ldirent->d_name); 55 m->enabled = false;
213 module_load (module_filename);
214 }
215 56
216 closedir (module_dir); 57 return fault_ok;
217} 58}
218 59
219/* 60module *
220 * module_unload() 61modules::find (char const * const name)
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 */
231void
232module_unload (module_t *m)
233{ 62{
234 node_t *n, *tn; 63 foreach (module *m, modlist ())
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 */
286void *
287module_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 */
324module_t *
325module_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)) 64 if (!strcmp (m->name, name))
334 return m; 65 return m;
335 }
336 66
337 return NULL; 67 return NULL;
338} 68}
339 69
340/* 70void
341 * module_find_published() 71modules::cleanup ()
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 */
352module_t *
353module_find_published (char *name)
354{ 72{
355 node_t *n; 73 list_type::iterator it = modlist().begin ();
74 list_type::iterator et = modlist().end ();
356 75
357 LIST_FOREACH (n, modules.head) 76 while (--et != it)
358 { 77 {
359 module_t *m = static_cast<module_t *> (n->data); 78 module *m = *et;
360 79 if (m->enabled)
361 if (!strcasecmp (m->header->name, name)) 80 m->fini ();
362 return m; 81 delete m;
363 } 82 }
364
365 return NULL;
366} 83}
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 */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines