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