]> jfr.im git - irc/quakenet/newserv.git/blob - core/modules.c
r729@blue (orig r504): slug | 2006-06-09 14:02:53 +0100
[irc/quakenet/newserv.git] / core / modules.c
1 /*
2 * modules.c:
3 *
4 * Provides functions for dealing with dynamic modules.
5 */
6
7 #include <stdlib.h>
8 #include <dlfcn.h>
9 #include "modules.h"
10 #include "../lib/array.h"
11 #include "../lib/sstring.h"
12 #include "../lib/irc_string.h"
13 #include "config.h"
14 #include "error.h"
15 #include <stdio.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <unistd.h>
19
20 array modules;
21
22 sstring *moddir;
23 sstring *modsuffix;
24
25 void modulerehash() {
26 int i;
27 sstring **mods;
28 array *autoloads;
29
30 if (moddir!=NULL)
31 freesstring(moddir);
32
33 if (modsuffix!=NULL)
34 freesstring(modsuffix);
35
36 moddir=getcopyconfigitem("core","moduledir",".",100);
37 modsuffix=getcopyconfigitem("core","modulesuffix",".so",5);
38
39 /* Check for auto-load modules */
40 autoloads=getconfigitems("core","loadmodule");
41 if (autoloads!=NULL) {
42 mods=(sstring **)(autoloads->content);
43 for (i=0;i<autoloads->cursi;i++) {
44 insmod(mods[i]->content);
45 }
46 }
47 }
48
49 void initmodules() {
50 array_init(&modules,sizeof(module));
51 array_setlim1(&modules,5);
52 array_setlim2(&modules,10);
53
54 moddir=NULL;
55 modsuffix=NULL;
56 modulerehash();
57 }
58
59 int insmod(char *modulename) {
60 int i, n;
61 module *mods;
62 char buf[1024], buf2[1024]; /* must be the same! */
63 const char *(*verinfo)(void);
64
65 delchars(modulename,"./\\;");
66
67 if (isloaded(modulename)) {
68 Error("core",ERR_DEBUG,"Tried to load already loaded module: %s",modulename);
69 return 1;
70 }
71
72 if (strlen(modulename)>100) {
73 Error("core",ERR_WARNING,"Module name too long: %s",modulename);
74 return 1;
75 }
76
77 i=array_getfreeslot(&modules);
78 mods=(module *)(modules.content);
79
80 sprintf(buf,"%s/%s%s",moddir->content,modulename,modsuffix->content);
81
82 for(;;) {
83 n = readlink(buf, buf2, sizeof(buf2));
84 if(n == -1) {
85 if(errno == EINVAL) {
86 break;
87 } else {
88 Error("core",ERR_ERROR,"Loading symlink module %s failed: %s",modulename, strerror(errno));
89 array_delslot(&modules,i);
90 return -1;
91 }
92 }
93
94 buf2[n] = '\0';
95 memcpy(buf, buf2, sizeof(buf));
96 }
97
98 mods[i].handle=dlopen(buf,RTLD_NOW|RTLD_GLOBAL);
99
100 if(mods[i].handle==NULL) {
101 Error("core",ERR_ERROR,"Loading module %s failed: %s",modulename,dlerror());
102 array_delslot(&modules,i);
103 return -1;
104 }
105
106 mods[i].name=getsstring(modulename,MODULENAMELEN);
107
108 verinfo=dlsym(mods[i].handle,"_version");
109 if(verinfo) {
110 mods[i].version=verinfo();
111 } else {
112 mods[i].version=NULL;
113 }
114
115 Error("core",ERR_INFO,"Loaded module %s OK.",modulename);
116
117 return 0;
118 }
119
120 int getindex(char *modulename) {
121 int i;
122 module *mods;
123
124 mods=(module *)(modules.content);
125 for(i=0;i<modules.cursi;i++)
126 if (!strcmp(mods[i].name->content,modulename))
127 return i;
128
129 return -1;
130 }
131
132 char *lsmod(int index) {
133 module *mods;
134
135 if (index < 0 || index >= modules.cursi)
136 return NULL;
137
138 mods=(module *)(modules.content);
139 return mods[index].name->content;
140 }
141
142 const char *lsmodver(int index) {
143 module *mods;
144
145 if (index < 0 || index >= modules.cursi)
146 return NULL;
147
148 mods=(module *)(modules.content);
149 return mods[index].version;
150 }
151
152 int isloaded(char *modulename) {
153 if (getindex(modulename)==-1)
154 return 0;
155 else
156 return 1;
157 }
158
159 int rmmod(char *modulename) {
160 int i;
161 module *mods;
162
163 delchars(modulename,"./\\;");
164
165 i=getindex(modulename);
166 if (i<0)
167 return 1;
168
169 mods=(module *)(modules.content);
170
171 #ifdef BROKEN_DLCLOSE
172 {
173 void (*fini)();
174 fini = dlsym(mods[i].handle, "__fini");
175 if(!dlerror())
176 fini();
177 }
178 #endif
179
180 dlclose(mods[i].handle);
181 freesstring(mods[i].name);
182 array_delslot(&modules,i);
183
184 Error("core",ERR_INFO,"Removed module %s.",modulename);
185
186 return 0;
187 }