]>
jfr.im git - irc/quakenet/newserv.git/blob - core/modules.c
4 * Provides functions for dealing with dynamic modules.
10 #include "../lib/array.h"
11 #include "../lib/sstring.h"
12 #include "../lib/irc_string.h"
13 #include "../lib/splitline.h"
22 #define DEPFILE "modules.dep"
24 #define MAXMODULES 100
26 /* Module dependency stuff.
28 * "parents" are modules we rely on in order to work.
29 * Whenever we load a module we must ensure all parents are present first.
31 * "children" are modules which rely on us.
32 * Whenever we remove a module, we must ensure all children are removed.
33 * If it's a reload, we will reload them afterwards.
35 * Now, depmod.pl cunningly arranges the file so that each modules' parents are
36 * always defined earlier in the file. So we can allocate and fill in the parents
37 * array as we read the file. Note that we can also arrange for numchildren to be
38 * correct on each node when we've finished.
40 * We then do a second pass. At each node, we allocate the space for the
41 * children array and reset numchildren to 0. We can also then populate our
42 * parents' children array with ourselves, using "numchildren" to get the
45 * At the end of the second pass we should have a correctly filled in array!
48 sstring
*safereload_str
;
49 schedule
*safereload_sched
;
53 unsigned int numparents
;
54 unsigned int numchildren
;
55 struct module_dep
**parents
;
56 struct module_dep
**children
;
57 unsigned int reloading
;
62 struct module_dep moduledeps
[MAXMODULES
];
63 unsigned int knownmodules
=0;
68 /* Clear out and free the dependencies. */
69 void clearmoduledeps() {
72 for (i
=0;i
<knownmodules
;i
++) {
73 if (moduledeps
[i
].parents
) {
74 free(moduledeps
[i
].parents
);
75 moduledeps
[i
].parents
=NULL
;
77 if (moduledeps
[i
].children
) {
78 free(moduledeps
[i
].children
);
79 moduledeps
[i
].children
=NULL
;
86 /* Get a pointer to the given module's dependency record. */
87 struct module_dep
*getmoduledep(const char *name
) {
90 for (i
=0;i
<knownmodules
;i
++) {
91 if (!strcmp(name
,moduledeps
[i
].name
->content
))
92 return &(moduledeps
[i
]);
98 /* Populate the dependency array. Read the monster description above for details.
99 * This relies on moddir being set, so call this after setting it up. */
100 void initmoduledeps() {
106 struct module_dep
*mdp
, *tmdp
;
109 sprintf(buf
,"%s/%s",moddir
->content
,DEPFILE
);
111 if (!(fp
=fopen(buf
,"r"))) {
112 Error("core",ERR_WARNING
,"Unable to open module dependency file: %s",buf
);
116 fgets(buf
, sizeof(buf
), fp
);
120 /* Chomp off that ruddy newline. */
121 for (ch
=buf
;*ch
;ch
++) {
122 if (*ch
=='\n' || *ch
=='\r') {
128 /* We have a space-delimited list of things. Whatever will we do with that? :) */
129 largc
=splitline(buf
,largv
,100,0);
134 /* Add us to the array */
137 Error("core",ERR_ERROR
,
138 "Too many modules in dependency file; rebuild with higher MAXMODULES. Module dependencies disabled.\n");
143 mdp
=&(moduledeps
[i
]);
145 mdp
->name
=getsstring(largv
[0],100);
146 mdp
->numparents
=largc
-1;
147 mdp
->numchildren
=0; /* peace, for now */
148 mdp
->parents
=malloc(mdp
->numparents
* sizeof(struct module_dep
*));
150 /* Fill in the parents array */
151 for (i
=0;i
<(largc
-1);i
++) {
152 if (!(mdp
->parents
[i
]=getmoduledep(largv
[i
+1]))) {
153 Error("core",ERR_WARNING
,"Couldn't find parent module %s of %s. Module dependencies disabled.",
154 largv
[i
+1],largv
[0]);
158 mdp
->parents
[i
]->numchildren
++; /* break the bad news */
163 for (i
=0;i
<knownmodules
;i
++) {
164 mdp
=&(moduledeps
[i
]);
166 /* Allocate child array */
167 if (mdp
->numchildren
) {
168 mdp
->children
=malloc(mdp
->numchildren
* sizeof(struct module_dep
*));
169 mdp
->numchildren
=0; /* if only real life were this simple */
172 /* Now fill in the children arrays of our parents (bear with me on this) */
173 for (j
=0;j
<mdp
->numparents
;j
++) {
174 tmdp
=mdp
->parents
[j
]; /* This is just... */
176 tmdp
->children
[tmdp
->numchildren
++]=mdp
; /* ... to give this line a chance at making sense */
182 void modulerehash() {
191 freesstring(modsuffix
);
195 moddir
=getcopyconfigitem("core","moduledir",".",100);
196 modsuffix
=getcopyconfigitem("core","modulesuffix",".so",5);
200 /* Check for auto-load modules */
201 autoloads
=getconfigitems("core","loadmodule");
202 if (autoloads
!=NULL
) {
203 mods
=(sstring
**)(autoloads
->content
);
204 for (i
=0;i
<autoloads
->cursi
;i
++) {
205 insmod(mods
[i
]->content
);
211 array_init(&modules
,sizeof(module));
212 array_setlim1(&modules
,5);
213 array_setlim2(&modules
,10);
220 int insmod(char *modulename
) {
224 const char *(*verinfo
)(void);
225 struct module_dep
*mdp
;
227 delchars(modulename
,"./\\;");
229 if (isloaded(modulename
)) {
230 Error("core",ERR_DEBUG
,"Tried to load already loaded module: %s",modulename
);
234 if (strlen(modulename
)>100) {
235 Error("core",ERR_WARNING
,"Module name too long: %s",modulename
);
239 if ((mdp
=getmoduledep(modulename
))) {
240 for (i
=0;i
<mdp
->numparents
;i
++) {
241 if (!isloaded(mdp
->parents
[i
]->name
->content
)) {
242 if (insmod(mdp
->parents
[i
]->name
->content
)) {
243 Error("core",ERR_WARNING
,"Error loading dependant module %s (needed by %s)",
244 mdp
->parents
[i
]->name
->content
,modulename
);
250 Error("core",ERR_WARNING
,"Loading module %s without dependency information.",modulename
);
253 i
=array_getfreeslot(&modules
);
254 mods
=(module *)(modules
.content
);
256 sprintf(buf
,"%s/%s%s",moddir
->content
,modulename
,modsuffix
->content
);
258 mods
[i
].handle
=dlopen(buf
,RTLD_NOW
|RTLD_GLOBAL
);
260 if(mods
[i
].handle
==NULL
) {
261 Error("core",ERR_ERROR
,"Loading module %s failed: %s",modulename
,dlerror());
262 array_delslot(&modules
,i
);
266 mods
[i
].name
=getsstring(modulename
,MODULENAMELEN
);
268 verinfo
=dlsym(mods
[i
].handle
,"_version");
270 mods
[i
].version
=verinfo();
272 mods
[i
].version
=NULL
;
275 Error("core",ERR_INFO
,"Loaded module %s OK.",modulename
);
280 int getindex(char *modulename
) {
284 mods
=(module *)(modules
.content
);
285 for(i
=0;i
<modules
.cursi
;i
++)
286 if (!strcmp(mods
[i
].name
->content
,modulename
))
292 char *lsmod(int index
) {
295 if (index
< 0 || index
>= modules
.cursi
)
298 mods
=(module *)(modules
.content
);
299 return mods
[index
].name
->content
;
302 const char *lsmodver(int index
) {
305 if (index
< 0 || index
>= modules
.cursi
)
308 mods
=(module *)(modules
.content
);
309 return mods
[index
].version
;
312 int isloaded(char *modulename
) {
313 if (getindex(modulename
)==-1)
320 int rmmod(char *modulename
) {
323 struct module_dep
*mdp
;
325 delchars(modulename
,"./\\;");
327 i
=getindex(modulename
);
331 if ((mdp
=getmoduledep(modulename
))) {
332 for (j
=0;j
<mdp
->numchildren
;j
++) {
333 if (isloaded(mdp
->children
[j
]->name
->content
)) {
334 if (rmmod(mdp
->children
[j
]->name
->content
)) {
335 Error("core",ERR_WARNING
,"Unable to remove child module %s (depends on %s)",
336 mdp
->children
[j
]->name
->content
, modulename
);
342 /* We may have removed other modules - reaquire the index number in case it has changed. */
343 i
=getindex(modulename
);
347 Error("core",ERR_WARNING
,"Removing module %s without dependency information",modulename
);
350 mods
=(module *)(modules
.content
);
352 #ifdef BROKEN_DLCLOSE
355 fini
= dlsym(mods
[i
].handle
, "__fini");
361 dlclose(mods
[i
].handle
);
362 freesstring(mods
[i
].name
);
363 array_delslot(&modules
,i
);
365 Error("core",ERR_INFO
,"Removed module %s.",modulename
);
370 /* Set the reload mark on the indicated module, if loaded, and all its
372 void setreloadmark(struct module_dep
*mdp
) {
375 if (!isloaded(mdp
->name
->content
))
378 for (i
=0;i
<mdp
->numchildren
;i
++)
379 setreloadmark(mdp
->children
[i
]);
384 /* preparereload: this function marks in the dependency tree all the
385 * modules which will be unloaded if this one is removed. */
386 void preparereload(char *modulename
) {
388 struct module_dep
*mdp
;
390 delchars(modulename
,"./\\;");
392 /* First, clear the mark off all dependant modules */
393 for (i
=0;i
<knownmodules
;i
++)
394 moduledeps
[i
].reloading
=0;
396 /* Do nothing if this module is not loaded */
397 i
=getindex(modulename
);
401 if ((mdp
=getmoduledep(modulename
))) {
406 /* reloadmarked: this function loads all the modules marked for reloading.
407 * The way the array is ordered means we will do this in the "right" order.
408 * This means we won't do an isloaded() check for each one - we shouldn't
409 * get any "already loaded" warnings so let them come out if they happen.
411 void reloadmarked(void) {
414 for (i
=0;i
<knownmodules
;i
++) {
415 if (moduledeps
[i
].reloading
) {
416 insmod(moduledeps
[i
].name
->content
);
421 void safereloadcallback(void *arg
) {
422 safereload_sched
=NULL
;
427 preparereload(safereload_str
->content
);
428 rmmod(safereload_str
->content
);
429 insmod(safereload_str
->content
);
432 freesstring(safereload_str
);
436 void safereload(char *themodule
) {
438 freesstring(safereload_str
);
440 safereload_str
=getsstring(themodule
, 100);
442 if (safereload_sched
)
443 deleteschedule(safereload_sched
, safereloadcallback
, NULL
);
445 scheduleoneshot(1, safereloadcallback
, NULL
);
448 void newserv_shutdown() {
451 while (modules
.cursi
) {
452 mods
=(module *)(modules
.content
);
453 rmmod(mods
[0].name
->content
);
456 Error("core",ERR_INFO
,"All modules removed. Exiting.");