ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/module.C
Revision: 1.2
Committed: Sat Jul 21 01:29:12 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
- moved to new documentation system
- fixed small build error

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * module.C: Module management.
3 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
4 pippijn 1.1 *
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     */