]> jfr.im git - solanum.git/blame - ircd/modules.c
modules: Revert mapi_register() to use ints
[solanum.git] / ircd / modules.c
CommitLineData
212380e3
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * modules.c: A module loader.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
212380e3
AC
23 */
24
25#include "stdinc.h"
212380e3 26#include "modules.h"
4016731b 27#include "logger.h"
212380e3
AC
28#include "ircd.h"
29#include "client.h"
30#include "send.h"
31#include "s_conf.h"
32#include "s_newconf.h"
33#include "numeric.h"
34#include "parse.h"
35#include "ircd_defs.h"
4562c604 36#include "match.h"
15feac53 37#include "s_serv.h"
8e9c6a75 38#include "capability.h"
212380e3 39
f272e7ab
AC
40#include <ltdl.h>
41
9abdcf1c
EM
42#ifndef LT_MODULE_EXT
43# error "Charybdis requires loadable module support."
44#endif
45
212380e3
AC
46struct module **modlist = NULL;
47
48static const char *core_module_table[] = {
431a1a27 49 "m_ban",
212380e3
AC
50 "m_die",
51 "m_error",
52 "m_join",
53 "m_kick",
54 "m_kill",
55 "m_message",
56 "m_mode",
57 "m_nick",
58 "m_part",
59 "m_quit",
60 "m_server",
212380e3
AC
61 "m_squit",
62 NULL
63};
64
81204be8
EM
65#define MOD_WARN_DELTA (90 * 86400) /* time in seconds, 86400 seconds in a day */
66
212380e3
AC
67#define MODS_INCREMENT 10
68int num_mods = 0;
69int max_mods = MODS_INCREMENT;
70
330fc5c1 71static rb_dlink_list mod_paths;
212380e3 72
3c7d6fcc
EM
73static void mo_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
74static void mo_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
75static void mo_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
76static void mo_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
77static void mo_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
78
79static void me_modload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
80static void me_modlist(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
81static void me_modreload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
82static void me_modunload(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
83static void me_modrestart(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
84
85static void do_modload(struct Client *, const char *);
86static void do_modunload(struct Client *, const char *);
87static void do_modreload(struct Client *, const char *);
88static void do_modlist(struct Client *, const char *);
89static void do_modrestart(struct Client *);
15feac53 90
212380e3 91struct Message modload_msgtab = {
7baa37a9 92 "MODLOAD", 0, 0, 0, 0,
15feac53 93 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
212380e3
AC
94};
95
96struct Message modunload_msgtab = {
7baa37a9 97 "MODUNLOAD", 0, 0, 0, 0,
15feac53 98 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
212380e3
AC
99};
100
101struct Message modreload_msgtab = {
7baa37a9 102 "MODRELOAD", 0, 0, 0, 0,
15feac53 103 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
212380e3
AC
104};
105
106struct Message modlist_msgtab = {
7baa37a9 107 "MODLIST", 0, 0, 0, 0,
15feac53 108 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
212380e3
AC
109};
110
111struct Message modrestart_msgtab = {
7baa37a9 112 "MODRESTART", 0, 0, 0, 0,
15feac53 113 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
212380e3
AC
114};
115
212380e3
AC
116void
117modules_init(void)
118{
f272e7ab
AC
119 if(lt_dlinit())
120 {
121 ilog(L_MAIN, "lt_dlinit failed");
122 exit(0);
123 }
124
212380e3
AC
125 mod_add_cmd(&modload_msgtab);
126 mod_add_cmd(&modunload_msgtab);
127 mod_add_cmd(&modreload_msgtab);
128 mod_add_cmd(&modlist_msgtab);
129 mod_add_cmd(&modrestart_msgtab);
130
131 /* Add the default paths we look in to the module system --nenolod */
4d8cfacd
AC
132 mod_add_path(ircd_paths[IRCD_PATH_MODULES]);
133 mod_add_path(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
212380e3
AC
134}
135
136/* mod_find_path()
137 *
138 * input - path
139 * output - none
140 * side effects - returns a module path from path
141 */
26c6ac3d 142static char *
212380e3
AC
143mod_find_path(const char *path)
144{
330fc5c1 145 rb_dlink_node *ptr;
26c6ac3d 146 char *mpath;
212380e3 147
5cefa1d6 148 RB_DLINK_FOREACH(ptr, mod_paths.head)
212380e3
AC
149 {
150 mpath = ptr->data;
151
26c6ac3d 152 if(!strcmp(path, mpath))
212380e3
AC
153 return mpath;
154 }
155
156 return NULL;
157}
158
159/* mod_add_path
160 *
161 * input - path
55abcbb2 162 * ouput -
212380e3
AC
163 * side effects - adds path to list
164 */
165void
166mod_add_path(const char *path)
167{
26c6ac3d 168 char *pathst;
212380e3
AC
169
170 if(mod_find_path(path))
171 return;
172
26c6ac3d 173 pathst = rb_strdup(path);
330fc5c1 174 rb_dlinkAddAlloc(pathst, &mod_paths);
212380e3
AC
175}
176
177/* mod_clear_paths()
178 *
179 * input -
180 * output -
181 * side effects - clear the lists of paths
182 */
183void
184mod_clear_paths(void)
185{
637c4932 186 rb_dlink_node *ptr, *next_ptr;
212380e3 187
637c4932 188 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
212380e3 189 {
637c4932 190 rb_free(ptr->data);
30106156 191 rb_free_rb_dlink_node(ptr);
212380e3
AC
192 }
193
194 mod_paths.head = mod_paths.tail = NULL;
195 mod_paths.length = 0;
196}
197
212380e3
AC
198/* findmodule_byname
199 *
aa483e55
EM
200 * input - module to load
201 * output - index of module on success, -1 on failure
202 * side effects - none
212380e3 203 */
212380e3
AC
204int
205findmodule_byname(const char *name)
206{
207 int i;
c9108ea0
AC
208 char name_ext[PATH_MAX + 1];
209
dd92c99b
AC
210 rb_strlcpy(name_ext, name, sizeof name_ext);
211 rb_strlcat(name_ext, LT_MODULE_EXT, sizeof name_ext);
212380e3
AC
212
213 for (i = 0; i < num_mods; i++)
214 {
215 if(!irccmp(modlist[i]->name, name))
216 return i;
c9108ea0
AC
217
218 if(!irccmp(modlist[i]->name, name_ext))
219 return i;
212380e3 220 }
c9108ea0 221
212380e3
AC
222 return -1;
223}
224
225/* load_all_modules()
226 *
227 * input -
228 * output -
229 * side effects -
230 */
231void
aa483e55 232load_all_modules(bool warn)
212380e3
AC
233{
234 DIR *system_module_dir = NULL;
235 struct dirent *ldirent = NULL;
236 char module_fq_name[PATH_MAX + 1];
1db8a313
EM
237 size_t module_ext_len = strlen(LT_MODULE_EXT);
238
212380e3
AC
239 modules_init();
240
1e170010 241 modlist = (struct module **) rb_malloc(sizeof(struct module *) * (MODS_INCREMENT));
212380e3
AC
242
243 max_mods = MODS_INCREMENT;
244
4d8cfacd 245 system_module_dir = opendir(ircd_paths[IRCD_PATH_AUTOLOAD_MODULES]);
212380e3
AC
246
247 if(system_module_dir == NULL)
248 {
4d8cfacd 249 ilog(L_MAIN, "Could not load modules from %s: %s", ircd_paths[IRCD_PATH_AUTOLOAD_MODULES], strerror(errno));
212380e3
AC
250 return;
251 }
252
253 while ((ldirent = readdir(system_module_dir)) != NULL)
254 {
66031753 255 size_t len = strlen(ldirent->d_name);
9abdcf1c 256
66031753
EM
257 if(len > module_ext_len &&
258 strncasecmp(ldirent->d_name + (len - module_ext_len), LT_MODULE_EXT, module_ext_len) == 0)
5203cba5 259 {
66031753
EM
260 (void) snprintf(module_fq_name, sizeof(module_fq_name), "%s%c%s",
261 ircd_paths[IRCD_PATH_AUTOLOAD_MODULES], RB_PATH_SEPARATOR, ldirent->d_name);
aa483e55 262 (void) load_a_module(module_fq_name, warn, MAPI_ORIGIN_CORE, false);
5203cba5 263 }
212380e3
AC
264
265 }
266 (void) closedir(system_module_dir);
267}
268
269/* load_core_modules()
270 *
271 * input -
272 * output -
273 * side effects - core modules are loaded, if any fail, kill ircd
274 */
275void
aa483e55 276load_core_modules(bool warn)
212380e3 277{
d74fa5b5 278 char module_name[PATH_MAX];
212380e3
AC
279 int i;
280
281
282 for (i = 0; core_module_table[i]; i++)
283 {
aa483e55
EM
284 snprintf(module_name, sizeof(module_name), "%s%c%s", ircd_paths[IRCD_PATH_MODULES], RB_PATH_SEPARATOR,
285 core_module_table[i]);
212380e3 286
aa483e55 287 if(load_a_module(module_name, warn, MAPI_ORIGIN_CORE, true) == false)
212380e3
AC
288 {
289 ilog(L_MAIN,
9abdcf1c
EM
290 "Error loading core module %s: terminating ircd",
291 core_module_table[i]);
212380e3
AC
292 exit(0);
293 }
294 }
295}
296
297/* load_one_module()
298 *
299 * input -
300 * output -
301 * side effects -
302 */
aa483e55
EM
303bool
304load_one_module(const char *path, int origin, bool coremodule)
212380e3 305{
d74fa5b5 306 char modpath[PATH_MAX];
330fc5c1 307 rb_dlink_node *pathst;
212380e3 308
503727d1 309 if (server_state_foreground)
55abcbb2 310 inotice("loading module %s ...", path);
212380e3 311
aa483e55 312 if(coremodule)
216d70e9 313 origin = MAPI_ORIGIN_CORE;
216d70e9 314
5cefa1d6 315 RB_DLINK_FOREACH(pathst, mod_paths.head)
212380e3 316 {
aa483e55
EM
317 struct stat statbuf;
318 const char *mpath = pathst->data;
212380e3 319
aa483e55 320 snprintf(modpath, sizeof(modpath), "%s%c%s%s", mpath, RB_PATH_SEPARATOR, path, LT_MODULE_EXT);
212380e3
AC
321 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
322 {
aa483e55 323 if(stat(modpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
212380e3 324 {
aa483e55
EM
325 /* Regular files only please */
326 return load_a_module(modpath, true, origin, coremodule);
212380e3
AC
327 }
328
329 }
330 }
331
332 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
aa483e55 333 return false;
212380e3
AC
334}
335
336
337/* load a module .. */
3c7d6fcc 338static void
4a84a763 339mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 340{
212380e3
AC
341 if(!IsOperAdmin(source_p))
342 {
343 sendto_one(source_p, form_str(ERR_NOPRIVS),
344 me.name, source_p->name, "admin");
3c7d6fcc 345 return;
212380e3
AC
346 }
347
15feac53
AC
348 if(parc > 2)
349 {
350 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
351 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
aa483e55 352 if(match(parv[2], me.name) == 0)
3c7d6fcc 353 return;
15feac53
AC
354 }
355
3c7d6fcc 356 do_modload(source_p, parv[1]);
15feac53
AC
357}
358
3c7d6fcc 359static void
4a84a763 360me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
361{
362 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
363 {
364 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
365 "to load modules on this server.");
3c7d6fcc 366 return;
15feac53
AC
367 }
368
3c7d6fcc 369 do_modload(source_p, parv[1]);
15feac53
AC
370}
371
3c7d6fcc
EM
372
373/* unload a module .. */
374static void
375mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53 376{
3c7d6fcc
EM
377 if(!IsOperAdmin(source_p))
378 {
379 sendto_one(source_p, form_str(ERR_NOPRIVS),
380 me.name, source_p->name, "admin");
381 return;
382 }
212380e3 383
3c7d6fcc 384 if(parc > 2)
212380e3 385 {
3c7d6fcc
EM
386 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
387 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
aa483e55 388 if(match(parv[2], me.name) == 0)
3c7d6fcc 389 return;
212380e3
AC
390 }
391
3c7d6fcc
EM
392 do_modunload(source_p, parv[1]);
393}
212380e3 394
3c7d6fcc
EM
395static void
396me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
397{
398 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
399 {
400 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
401 "to load modules on this server.");
402 return;
403 }
212380e3 404
3c7d6fcc 405 do_modunload(source_p, parv[1]);
212380e3
AC
406}
407
3c7d6fcc
EM
408/* unload and load in one! */
409static void
410mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 411{
212380e3
AC
412 if(!IsOperAdmin(source_p))
413 {
414 sendto_one(source_p, form_str(ERR_NOPRIVS),
415 me.name, source_p->name, "admin");
3c7d6fcc 416 return;
212380e3
AC
417 }
418
15feac53
AC
419 if(parc > 2)
420 {
421 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
3c7d6fcc 422 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
aa483e55 423 if(match(parv[2], me.name) == 0)
3c7d6fcc 424 return;
15feac53
AC
425 }
426
3c7d6fcc 427 do_modreload(source_p, parv[1]);
15feac53
AC
428}
429
3c7d6fcc
EM
430static void
431me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
432{
433 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
434 {
435 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
436 "to load modules on this server.");
3c7d6fcc 437 return;
15feac53
AC
438 }
439
3c7d6fcc 440 do_modreload(source_p, parv[1]);
15feac53
AC
441}
442
3c7d6fcc
EM
443/* list modules .. */
444static void
445mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53 446{
3c7d6fcc 447 if(!IsOperAdmin(source_p))
212380e3 448 {
3c7d6fcc
EM
449 sendto_one(source_p, form_str(ERR_NOPRIVS),
450 me.name, source_p->name, "admin");
451 return;
212380e3
AC
452 }
453
3c7d6fcc 454 if(parc > 2)
212380e3 455 {
3c7d6fcc
EM
456 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
457 "ENCAP %s MODLIST %s", parv[2], parv[1]);
aa483e55 458 if(match(parv[2], me.name) == 0)
3c7d6fcc 459 return;
212380e3
AC
460 }
461
3c7d6fcc
EM
462 do_modlist(source_p, parc > 1 ? parv[1] : 0);
463}
464
465static void
466me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
467{
468 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
212380e3 469 {
3c7d6fcc
EM
470 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
471 "to load modules on this server.");
472 return;
212380e3 473 }
5366977b 474
3c7d6fcc 475 do_modlist(source_p, parv[1]);
212380e3
AC
476}
477
3c7d6fcc
EM
478/* unload and reload all modules */
479static void
480mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 481{
212380e3
AC
482 if(!IsOperAdmin(source_p))
483 {
484 sendto_one(source_p, form_str(ERR_NOPRIVS),
485 me.name, source_p->name, "admin");
3c7d6fcc 486 return;
212380e3
AC
487 }
488
3c7d6fcc 489 if(parc > 1)
15feac53 490 {
3c7d6fcc
EM
491 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
492 "ENCAP %s MODRESTART", parv[1]);
aa483e55 493 if(match(parv[1], me.name) == 0)
3c7d6fcc 494 return;
15feac53
AC
495 }
496
3c7d6fcc 497 do_modrestart(source_p);
15feac53
AC
498}
499
3c7d6fcc
EM
500static void
501me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
502{
503 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
504 {
505 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
506 "to load modules on this server.");
3c7d6fcc 507 return;
15feac53
AC
508 }
509
3c7d6fcc 510 do_modrestart(source_p);
15feac53
AC
511}
512
3c7d6fcc
EM
513static void
514do_modload(struct Client *source_p, const char *module)
515{
516 char *m_bn = rb_basename(module);
517 int origin;
518
519 if(findmodule_byname(m_bn) != -1)
520 {
521 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
522 rb_free(m_bn);
523 return;
524 }
525
526 origin = strcmp(module, m_bn) == 0 ? MAPI_ORIGIN_CORE : MAPI_ORIGIN_EXTENSION;
aa483e55 527 load_one_module(module, origin, false);
3c7d6fcc
EM
528
529 rb_free(m_bn);
530}
531
532static void
533do_modunload(struct Client *source_p, const char *module)
534{
535 int modindex;
536 char *m_bn = rb_basename(module);
537
538 if((modindex = findmodule_byname(m_bn)) == -1)
539 {
540 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
541 rb_free(m_bn);
542 return;
543 }
544
aa483e55 545 if(modlist[modindex]->core)
3c7d6fcc
EM
546 {
547 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
548 rb_free(m_bn);
549 return;
550 }
551
aa483e55 552 if(unload_one_module(m_bn, true) == false)
3c7d6fcc 553 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
3c7d6fcc
EM
554
555 rb_free(m_bn);
556}
557
558static void
15feac53
AC
559do_modreload(struct Client *source_p, const char *module)
560{
561 int modindex;
562 int check_core;
563 char *m_bn = rb_basename(module);
212380e3
AC
564
565 if((modindex = findmodule_byname(m_bn)) == -1)
566 {
5366977b 567 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 568 rb_free(m_bn);
3c7d6fcc 569 return;
212380e3
AC
570 }
571
572 check_core = modlist[modindex]->core;
573
aa483e55 574 if(unload_one_module(m_bn, true) == false)
212380e3 575 {
5366977b 576 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 577 rb_free(m_bn);
3c7d6fcc 578 return;
212380e3
AC
579 }
580
aa483e55 581 if((load_one_module(m_bn, modlist[modindex]->origin, check_core) == false) && check_core)
212380e3 582 {
15feac53 583 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
7d778d51
AC
584 "Error reloading core module: %s: terminating ircd", m_bn);
585 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
212380e3
AC
586 exit(0);
587 }
588
637c4932 589 rb_free(m_bn);
212380e3
AC
590}
591
3c7d6fcc
EM
592static void
593do_modrestart(struct Client *source_p)
212380e3 594{
3c7d6fcc 595 int modnum;
212380e3 596
3c7d6fcc 597 sendto_one_notice(source_p, ":Reloading all modules");
15feac53 598
3c7d6fcc
EM
599 modnum = num_mods;
600 while (num_mods)
aa483e55 601 unload_one_module(modlist[0]->name, false);
15feac53 602
c0483ac1
EM
603 load_all_modules(false);
604 load_core_modules(false);
605 rehash(false);
15feac53 606
3c7d6fcc
EM
607 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
608 "Module Restart: %d modules unloaded, %d modules loaded",
609 modnum, num_mods);
610 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
15feac53
AC
611}
612
3c7d6fcc 613static void
15feac53
AC
614do_modlist(struct Client *source_p, const char *pattern)
615{
616 int i;
617
212380e3
AC
618 for (i = 0; i < num_mods; i++)
619 {
978b7232
EM
620 const char *origin;
621 switch (modlist[i]->origin)
622 {
623 case MAPI_ORIGIN_EXTENSION:
624 origin = "extension";
625 break;
626 case MAPI_ORIGIN_CORE:
627 origin = "builtin";
628 break;
629 default:
630 origin = "unknown";
631 break;
632 }
633
15feac53 634 if(pattern)
212380e3 635 {
15feac53 636 if(match(pattern, modlist[i]->name))
212380e3
AC
637 {
638 sendto_one(source_p, form_str(RPL_MODLIST),
639 me.name, source_p->name,
640 modlist[i]->name,
978b7232
EM
641 (unsigned long)(uintptr_t)modlist[i]->address, origin,
642 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
212380e3
AC
643 }
644 }
645 else
646 {
647 sendto_one(source_p, form_str(RPL_MODLIST),
648 me.name, source_p->name, modlist[i]->name,
978b7232
EM
649 (unsigned long)(uintptr_t)modlist[i]->address, origin,
650 modlist[i]->core ? " (core)" : "", modlist[i]->version, modlist[i]->description);
212380e3
AC
651 }
652 }
653
654 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
15feac53
AC
655}
656
212380e3
AC
657static void increase_modlist(void);
658
659#define MODS_INCREMENT 10
660
661static char unknown_ver[] = "<unknown>";
8e9c6a75 662static char unknown_description[] = "<none>";
212380e3 663
212380e3
AC
664/* unload_one_module()
665 *
666 * inputs - name of module to unload
aa483e55
EM
667 * - true to say modules unloaded, false to not
668 * output - true if successful, false if error
212380e3
AC
669 * side effects - module is unloaded
670 */
aa483e55
EM
671bool
672unload_one_module(const char *name, bool warn)
212380e3
AC
673{
674 int modindex;
675
676 if((modindex = findmodule_byname(name)) == -1)
aa483e55 677 return false;
212380e3
AC
678
679 /*
680 ** XXX - The type system in C does not allow direct conversion between
681 ** data and function pointers, but as it happens, most C compilers will
55abcbb2
KB
682 ** safely do this, however it is a theoretical overlow to cast as we
683 ** must do here. I have library functions to take care of this, but
684 ** despite being more "correct" for the C language, this is more
212380e3
AC
685 ** practical. Removing the abuse of the ability to cast ANY pointer
686 ** to and from an integer value here will break some compilers.
687 ** -jmallett
688 */
689 /* Left the comment in but the code isn't here any more -larne */
690 switch (modlist[modindex]->mapi_version)
691 {
692 case 1:
693 {
694 struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
695 if(mheader->mapi_command_list)
696 {
697 struct Message **m;
698 for (m = mheader->mapi_command_list; *m; ++m)
699 mod_del_cmd(*m);
700 }
701
702 /* hook events are never removed, we simply lose the
703 * ability to call them --fl
704 */
705 if(mheader->mapi_hfn_list)
706 {
707 mapi_hfn_list_av1 *m;
708 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
709 remove_hook(m->hapi_name, m->fn);
710 }
711
712 if(mheader->mapi_unregister)
713 mheader->mapi_unregister();
714 break;
715 }
8e9c6a75
EM
716 case 2:
717 {
718 struct mapi_mheader_av2 *mheader = modlist[modindex]->mapi_header;
719
720 /* XXX duplicate code :( */
721 if(mheader->mapi_command_list)
722 {
723 struct Message **m;
724 for (m = mheader->mapi_command_list; *m; ++m)
725 mod_del_cmd(*m);
726 }
727
728 /* hook events are never removed, we simply lose the
729 * ability to call them --fl
730 */
731 if(mheader->mapi_hfn_list)
732 {
733 mapi_hfn_list_av1 *m;
734 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
735 remove_hook(m->hapi_name, m->fn);
736 }
737
738 if(mheader->mapi_unregister)
739 mheader->mapi_unregister();
740
741 if(mheader->mapi_cap_list)
742 {
743 mapi_cap_list_av2 *m;
744 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
745 {
746 struct CapabilityIndex *idx;
747
978b7232 748 switch (m->cap_index)
8e9c6a75
EM
749 {
750 case MAPI_CAP_CLIENT:
751 idx = cli_capindex;
752 break;
753 case MAPI_CAP_SERVER:
754 idx = serv_capindex;
755 break;
756 default:
757 sendto_realops_snomask(SNO_GENERAL, L_ALL,
758 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
759 m->cap_index, m->cap_name, modlist[modindex]->name);
760 ilog(L_MAIN,
761 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
762 m->cap_index, m->cap_name, modlist[modindex]->name);
763 continue;
764 }
765
766 capability_orphan(idx, m->cap_name);
767 }
768 }
769 }
212380e3
AC
770 default:
771 sendto_realops_snomask(SNO_GENERAL, L_ALL,
772 "Unknown/unsupported MAPI version %d when unloading %s!",
773 modlist[modindex]->mapi_version, modlist[modindex]->name);
774 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
775 modlist[modindex]->mapi_version, modlist[modindex]->name);
776 break;
777 }
778
f272e7ab 779 lt_dlclose(modlist[modindex]->address);
212380e3 780
637c4932 781 rb_free(modlist[modindex]->name);
55d5f797 782 rb_free(modlist[modindex]);
f54e1a8f 783 memmove(&modlist[modindex], &modlist[modindex + 1],
1e170010 784 sizeof(struct module *) * ((num_mods - 1) - modindex));
212380e3
AC
785
786 if(num_mods != 0)
787 num_mods--;
788
aa483e55 789 if(warn)
212380e3
AC
790 {
791 ilog(L_MAIN, "Module %s unloaded", name);
792 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
793 }
794
aa483e55 795 return true;
212380e3
AC
796}
797
212380e3
AC
798/*
799 * load_a_module()
800 *
aa483e55
EM
801 * inputs - path name of module, bool to notice, int of origin, bool if core
802 * output - false if error true if success
212380e3
AC
803 * side effects - loads a module if successful
804 */
aa483e55
EM
805bool
806load_a_module(const char *path, bool warn, int origin, bool core)
212380e3 807{
f272e7ab 808 lt_dlhandle tmpptr;
212380e3 809 char *mod_basename;
8e9c6a75 810 const char *ver, *description = NULL;
212380e3
AC
811
812 int *mapi_version;
813
b7a689d1 814 mod_basename = rb_basename(path);
212380e3 815
9abdcf1c 816 tmpptr = lt_dlopenext(path);
212380e3
AC
817
818 if(tmpptr == NULL)
819 {
f272e7ab 820 const char *err = lt_dlerror();
212380e3
AC
821
822 sendto_realops_snomask(SNO_GENERAL, L_ALL,
823 "Error loading module %s: %s", mod_basename, err);
824 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
637c4932 825 rb_free(mod_basename);
aa483e55 826 return false;
212380e3
AC
827 }
828
212380e3
AC
829 /*
830 * _mheader is actually a struct mapi_mheader_*, but mapi_version
831 * is always the first member of this structure, so we treate it
832 * as a single int in order to determine the API version.
833 * -larne.
834 */
f272e7ab 835 mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "_mheader");
212380e3 836 if((mapi_version == NULL
f272e7ab 837 && (mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "__mheader")) == NULL)
212380e3
AC
838 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
839 {
840 sendto_realops_snomask(SNO_GENERAL, L_ALL,
841 "Data format error: module %s has no MAPI header.",
842 mod_basename);
843 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
f272e7ab 844 (void) lt_dlclose(tmpptr);
637c4932 845 rb_free(mod_basename);
aa483e55 846 return false;
212380e3
AC
847 }
848
849 switch (MAPI_VERSION(*mapi_version))
850 {
851 case 1:
852 {
29c92cf9 853 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *)(void *)mapi_version; /* see above */
212380e3
AC
854 if(mheader->mapi_register && (mheader->mapi_register() == -1))
855 {
856 ilog(L_MAIN, "Module %s indicated failure during load.",
857 mod_basename);
858 sendto_realops_snomask(SNO_GENERAL, L_ALL,
859 "Module %s indicated failure during load.",
860 mod_basename);
f272e7ab 861 lt_dlclose(tmpptr);
637c4932 862 rb_free(mod_basename);
aa483e55 863 return false;
212380e3
AC
864 }
865 if(mheader->mapi_command_list)
866 {
867 struct Message **m;
868 for (m = mheader->mapi_command_list; *m; ++m)
869 mod_add_cmd(*m);
870 }
871
872 if(mheader->mapi_hook_list)
873 {
874 mapi_hlist_av1 *m;
875 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
876 *m->hapi_id = register_hook(m->hapi_name);
877 }
878
879 if(mheader->mapi_hfn_list)
880 {
881 mapi_hfn_list_av1 *m;
882 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
883 add_hook(m->hapi_name, m->fn);
884 }
885
886 ver = mheader->mapi_module_version;
887 break;
888 }
8e9c6a75
EM
889 case 2:
890 {
891 struct mapi_mheader_av2 *mheader = (struct mapi_mheader_av2 *)(void *)mapi_version; /* see above */
212380e3 892
8e9c6a75 893 /* XXX duplicated code :( */
5eb3d7a7 894 if(mheader->mapi_register && (mheader->mapi_register() == -1))
8e9c6a75
EM
895 {
896 ilog(L_MAIN, "Module %s indicated failure during load.",
81204be8 897 mod_basename);
8e9c6a75
EM
898 sendto_realops_snomask(SNO_GENERAL, L_ALL,
899 "Module %s indicated failure during load.",
900 mod_basename);
901 lt_dlclose(tmpptr);
902 rb_free(mod_basename);
aa483e55 903 return false;
8e9c6a75 904 }
81204be8
EM
905
906 /* Basic date code checks
907 *
908 * Don't make them fatal, but do complain about differences within a certain time frame.
909 * Later on if there are major API changes we can add fatal checks.
910 * -- Elizafox
911 */
912 if(mheader->mapi_datecode != datecode && mheader->mapi_datecode > 0)
913 {
3089f59c 914 long int delta = datecode - mheader->mapi_datecode;
81204be8
EM
915 if (delta > MOD_WARN_DELTA)
916 {
917 delta /= 86400;
881acf00 918 iwarn("Module %s build date is out of sync with ircd build date by %ld days, expect problems",
81204be8
EM
919 mod_basename, delta);
920 sendto_realops_snomask(SNO_GENERAL, L_ALL,
921 "Module %s build date is out of sync with ircd build date by %ld days, expect problems",
922 mod_basename, delta);
923 }
924 }
925
8e9c6a75
EM
926 if(mheader->mapi_command_list)
927 {
928 struct Message **m;
929 for (m = mheader->mapi_command_list; *m; ++m)
930 mod_add_cmd(*m);
931 }
932
933 if(mheader->mapi_hook_list)
934 {
935 mapi_hlist_av1 *m;
936 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
937 *m->hapi_id = register_hook(m->hapi_name);
938 }
939
940 if(mheader->mapi_hfn_list)
941 {
942 mapi_hfn_list_av1 *m;
943 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
944 add_hook(m->hapi_name, m->fn);
945 }
946
947 /* New in MAPI v2 - version replacement */
948 ver = mheader->mapi_module_version ? mheader->mapi_module_version : ircd_version;
949 description = mheader->mapi_module_description;
950
951 if(mheader->mapi_cap_list)
952 {
953 mapi_cap_list_av2 *m;
954 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
955 {
956 struct CapabilityIndex *idx;
957 int result;
958
978b7232 959 switch (m->cap_index)
8e9c6a75
EM
960 {
961 case MAPI_CAP_CLIENT:
962 idx = cli_capindex;
963 break;
964 case MAPI_CAP_SERVER:
965 idx = serv_capindex;
966 break;
967 default:
968 sendto_realops_snomask(SNO_GENERAL, L_ALL,
969 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
970 m->cap_index, m->cap_name, mod_basename);
971 ilog(L_MAIN,
972 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
973 m->cap_index, m->cap_name, mod_basename);
974 continue;
975 }
976
977 result = capability_put(idx, m->cap_name, m->cap_ownerdata);
978 if (m->cap_id != NULL)
979 *(m->cap_id) = result;
980 }
981 }
982 }
0e5bf029
EM
983
984 break;
212380e3
AC
985 default:
986 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
987 mod_basename, MAPI_VERSION(*mapi_version));
988 sendto_realops_snomask(SNO_GENERAL, L_ALL,
989 "Module %s has unknown/unsupported MAPI version %d.",
990 mod_basename, *mapi_version);
f272e7ab 991 lt_dlclose(tmpptr);
637c4932 992 rb_free(mod_basename);
aa483e55 993 return false;
212380e3
AC
994 }
995
996 if(ver == NULL)
997 ver = unknown_ver;
998
8e9c6a75
EM
999 if(description == NULL)
1000 description = unknown_description;
1001
212380e3
AC
1002 increase_modlist();
1003
eddc2ab6 1004 modlist[num_mods] = rb_malloc(sizeof(struct module));
212380e3
AC
1005 modlist[num_mods]->address = tmpptr;
1006 modlist[num_mods]->version = ver;
0eb7d9c0 1007 modlist[num_mods]->description = description;
212380e3 1008 modlist[num_mods]->core = core;
47a03750 1009 modlist[num_mods]->name = rb_strdup(mod_basename);
212380e3
AC
1010 modlist[num_mods]->mapi_header = mapi_version;
1011 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
c63aeb44 1012 modlist[num_mods]->origin = origin;
212380e3
AC
1013 num_mods++;
1014
aa483e55 1015 if(warn)
212380e3 1016 {
c63aeb44
EM
1017 const char *o;
1018
978b7232 1019 switch (origin)
c63aeb44 1020 {
c63aeb44
EM
1021 case MAPI_ORIGIN_EXTENSION:
1022 o = "extension";
1023 break;
1024 case MAPI_ORIGIN_CORE:
1025 o = "core";
1026 break;
1027 default:
1028 o = "unknown";
1029 break;
1030 }
1031
212380e3 1032 sendto_realops_snomask(SNO_GENERAL, L_ALL,
02831b6f 1033 "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
c63aeb44 1034 mod_basename, ver, MAPI_VERSION(*mapi_version), o, description,
02831b6f
AC
1035 (void *) tmpptr);
1036 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d; origin: %s; description: \"%s\"] loaded at %p",
1037 mod_basename, ver, MAPI_VERSION(*mapi_version), o, description, (void *) tmpptr);
212380e3 1038 }
637c4932 1039 rb_free(mod_basename);
aa483e55 1040 return true;
212380e3
AC
1041}
1042
1043/*
1044 * increase_modlist
1045 *
1046 * inputs - NONE
1047 * output - NONE
1048 * side effects - expand the size of modlist if necessary
1049 */
1050static void
1051increase_modlist(void)
1052{
1053 struct module **new_modlist = NULL;
1054
1055 if((num_mods + 1) < max_mods)
1056 return;
1057
1e170010 1058 new_modlist = (struct module **) rb_malloc(sizeof(struct module *) *
212380e3 1059 (max_mods + MODS_INCREMENT));
1e170010 1060 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module *) * num_mods);
212380e3 1061
637c4932 1062 rb_free(modlist);
212380e3
AC
1063 modlist = new_modlist;
1064 max_mods += MODS_INCREMENT;
1065}