]> jfr.im git - solanum.git/blame - ircd/modules.c
modules: add origin field to V2
[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);
246 (void) load_a_module(module_fq_name, warn, 0);
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
AC
270
271 if(load_a_module(module_name, warn, 1) == -1)
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
288load_one_module(const char *path, int coremodule)
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
5cefa1d6 299 RB_DLINK_FOREACH(pathst, mod_paths.head)
212380e3
AC
300 {
301 mpath = pathst->data;
302
5203cba5 303 snprintf(modpath, sizeof(modpath), "%s/%s", mpath, path);
212380e3
AC
304 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
305 {
306 if(stat(modpath, &statbuf) == 0)
307 {
308 if(S_ISREG(statbuf.st_mode))
309 {
310 /* Regular files only please */
311 if(coremodule)
312 return load_a_module(modpath, 1, 1);
313 else
314 return load_a_module(modpath, 1, 0);
315 }
316 }
317
318 }
319 }
320
321 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
322 return -1;
323}
324
325
326/* load a module .. */
327static int
4a84a763 328mo_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 329{
212380e3
AC
330 if(!IsOperAdmin(source_p))
331 {
332 sendto_one(source_p, form_str(ERR_NOPRIVS),
333 me.name, source_p->name, "admin");
334 return 0;
335 }
336
15feac53
AC
337 if(parc > 2)
338 {
339 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
340 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
341 if (match(parv[2], me.name) == 0)
342 return 0;
343 }
344
345 return do_modload(source_p, parv[1]);
346}
347
348static int
4a84a763 349me_modload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
350{
351 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
352 {
353 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
354 "to load modules on this server.");
355 return 0;
356 }
357
358 return do_modload(source_p, parv[1]);
359}
360
361static int
362do_modload(struct Client *source_p, const char *module)
363{
364 char *m_bn = rb_basename(module);
212380e3
AC
365
366 if(findmodule_byname(m_bn) != -1)
367 {
5366977b 368 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
637c4932 369 rb_free(m_bn);
212380e3
AC
370 return 0;
371 }
372
15feac53 373 load_one_module(module, 0);
212380e3 374
637c4932 375 rb_free(m_bn);
212380e3
AC
376
377 return 0;
378}
379
380
381/* unload a module .. */
382static int
4a84a763 383mo_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 384{
212380e3
AC
385 if(!IsOperAdmin(source_p))
386 {
387 sendto_one(source_p, form_str(ERR_NOPRIVS),
388 me.name, source_p->name, "admin");
389 return 0;
390 }
391
15feac53
AC
392 if(parc > 2)
393 {
394 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
395 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
396 if (match(parv[2], me.name) == 0)
397 return 0;
398 }
399
400 return do_modunload(source_p, parv[1]);
401}
402
403static int
4a84a763 404me_modunload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
405{
406 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
407 {
408 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
409 "to load modules on this server.");
410 return 0;
411 }
412
413 return do_modunload(source_p, parv[1]);
414}
415
416static int
417do_modunload(struct Client *source_p, const char *module)
418{
419 int modindex;
420 char *m_bn = rb_basename(module);
212380e3
AC
421
422 if((modindex = findmodule_byname(m_bn)) == -1)
423 {
5366977b 424 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 425 rb_free(m_bn);
212380e3
AC
426 return 0;
427 }
428
429 if(modlist[modindex]->core == 1)
430 {
5366977b 431 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
637c4932 432 rb_free(m_bn);
212380e3
AC
433 return 0;
434 }
435
436 if(unload_one_module(m_bn, 1) == -1)
437 {
5366977b 438 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
212380e3 439 }
5366977b 440
637c4932 441 rb_free(m_bn);
212380e3
AC
442 return 0;
443}
444
445/* unload and load in one! */
446static int
4a84a763 447mo_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 448{
212380e3
AC
449 if(!IsOperAdmin(source_p))
450 {
451 sendto_one(source_p, form_str(ERR_NOPRIVS),
452 me.name, source_p->name, "admin");
453 return 0;
454 }
455
15feac53
AC
456 if(parc > 2)
457 {
458 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
459 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
460 if (match(parv[2], me.name) == 0)
461 return 0;
462 }
463
464 return do_modreload(source_p, parv[1]);
465}
466
467static int
4a84a763 468me_modreload(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
469{
470 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
471 {
472 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
473 "to load modules on this server.");
474 return 0;
475 }
476
477 return do_modreload(source_p, parv[1]);
478}
479
480static int
481do_modreload(struct Client *source_p, const char *module)
482{
483 int modindex;
484 int check_core;
485 char *m_bn = rb_basename(module);
212380e3
AC
486
487 if((modindex = findmodule_byname(m_bn)) == -1)
488 {
5366977b 489 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 490 rb_free(m_bn);
212380e3
AC
491 return 0;
492 }
493
494 check_core = modlist[modindex]->core;
495
496 if(unload_one_module(m_bn, 1) == -1)
497 {
5366977b 498 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
637c4932 499 rb_free(m_bn);
212380e3
AC
500 return 0;
501 }
502
7d778d51 503 if((load_one_module(m_bn, check_core) == -1) && check_core)
212380e3 504 {
15feac53 505 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
7d778d51
AC
506 "Error reloading core module: %s: terminating ircd", m_bn);
507 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
212380e3
AC
508 exit(0);
509 }
510
637c4932 511 rb_free(m_bn);
212380e3
AC
512 return 0;
513}
514
515/* list modules .. */
516static int
4a84a763 517mo_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 518{
212380e3
AC
519 if(!IsOperAdmin(source_p))
520 {
521 sendto_one(source_p, form_str(ERR_NOPRIVS),
522 me.name, source_p->name, "admin");
523 return 0;
524 }
525
15feac53
AC
526 if(parc > 2)
527 {
528 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
529 "ENCAP %s MODLIST %s", parv[2], parv[1]);
530 if (match(parv[2], me.name) == 0)
531 return 0;
532 }
533
534 return do_modlist(source_p, parc > 1 ? parv[1] : 0);
535}
536
537static int
4a84a763 538me_modlist(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
539{
540 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
541 {
542 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
543 "to load modules on this server.");
544 return 0;
545 }
546
547 return do_modlist(source_p, parv[1]);
548}
549
550static int
551do_modlist(struct Client *source_p, const char *pattern)
552{
553 int i;
554
212380e3
AC
555 for (i = 0; i < num_mods; i++)
556 {
15feac53 557 if(pattern)
212380e3 558 {
15feac53 559 if(match(pattern, modlist[i]->name))
212380e3
AC
560 {
561 sendto_one(source_p, form_str(RPL_MODLIST),
562 me.name, source_p->name,
563 modlist[i]->name,
a9f12814 564 (unsigned long)(uintptr_t)modlist[i]->address,
2ab24be6 565 modlist[i]->version, modlist[i]->description, modlist[i]->core ? " (core)" : "");
212380e3
AC
566 }
567 }
568 else
569 {
570 sendto_one(source_p, form_str(RPL_MODLIST),
571 me.name, source_p->name, modlist[i]->name,
2ab24be6
EM
572 (unsigned long)(uintptr_t)modlist[i]->address,
573 modlist[i]->version, modlist[i]->description, modlist[i]->core ? " (core)" : "");
212380e3
AC
574 }
575 }
576
577 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
578 return 0;
579}
580
581/* unload and reload all modules */
582static int
4a84a763 583mo_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
212380e3 584{
212380e3
AC
585 if(!IsOperAdmin(source_p))
586 {
587 sendto_one(source_p, form_str(ERR_NOPRIVS),
588 me.name, source_p->name, "admin");
589 return 0;
590 }
591
15feac53
AC
592 if(parc > 1)
593 {
594 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
595 "ENCAP %s MODRESTART", parv[1]);
596 if (match(parv[1], me.name) == 0)
597 return 0;
598 }
599
600 return do_modrestart(source_p);
601}
602
603static int
4a84a763 604me_modrestart(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
15feac53
AC
605{
606 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
607 {
608 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
609 "to load modules on this server.");
610 return 0;
611 }
612
613 return do_modrestart(source_p);
614}
615
616static int
617do_modrestart(struct Client *source_p)
618{
619 int modnum;
620
5366977b 621 sendto_one_notice(source_p, ":Reloading all modules");
212380e3
AC
622
623 modnum = num_mods;
624 while (num_mods)
625 unload_one_module(modlist[0]->name, 0);
626
627 load_all_modules(0);
628 load_core_modules(0);
629 rehash(0);
630
15feac53 631 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
212380e3
AC
632 "Module Restart: %d modules unloaded, %d modules loaded",
633 modnum, num_mods);
634 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
635 return 0;
636}
637
638
212380e3
AC
639static void increase_modlist(void);
640
641#define MODS_INCREMENT 10
642
643static char unknown_ver[] = "<unknown>";
8e9c6a75 644static char unknown_description[] = "<none>";
212380e3 645
212380e3
AC
646/* unload_one_module()
647 *
648 * inputs - name of module to unload
649 * - 1 to say modules unloaded, 0 to not
650 * output - 0 if successful, -1 if error
651 * side effects - module is unloaded
652 */
653int
654unload_one_module(const char *name, int warn)
655{
656 int modindex;
657
658 if((modindex = findmodule_byname(name)) == -1)
659 return -1;
660
661 /*
662 ** XXX - The type system in C does not allow direct conversion between
663 ** data and function pointers, but as it happens, most C compilers will
55abcbb2
KB
664 ** safely do this, however it is a theoretical overlow to cast as we
665 ** must do here. I have library functions to take care of this, but
666 ** despite being more "correct" for the C language, this is more
212380e3
AC
667 ** practical. Removing the abuse of the ability to cast ANY pointer
668 ** to and from an integer value here will break some compilers.
669 ** -jmallett
670 */
671 /* Left the comment in but the code isn't here any more -larne */
672 switch (modlist[modindex]->mapi_version)
673 {
674 case 1:
675 {
676 struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
677 if(mheader->mapi_command_list)
678 {
679 struct Message **m;
680 for (m = mheader->mapi_command_list; *m; ++m)
681 mod_del_cmd(*m);
682 }
683
684 /* hook events are never removed, we simply lose the
685 * ability to call them --fl
686 */
687 if(mheader->mapi_hfn_list)
688 {
689 mapi_hfn_list_av1 *m;
690 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
691 remove_hook(m->hapi_name, m->fn);
692 }
693
694 if(mheader->mapi_unregister)
695 mheader->mapi_unregister();
696 break;
697 }
8e9c6a75
EM
698 case 2:
699 {
700 struct mapi_mheader_av2 *mheader = modlist[modindex]->mapi_header;
701
702 /* XXX duplicate code :( */
703 if(mheader->mapi_command_list)
704 {
705 struct Message **m;
706 for (m = mheader->mapi_command_list; *m; ++m)
707 mod_del_cmd(*m);
708 }
709
710 /* hook events are never removed, we simply lose the
711 * ability to call them --fl
712 */
713 if(mheader->mapi_hfn_list)
714 {
715 mapi_hfn_list_av1 *m;
716 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
717 remove_hook(m->hapi_name, m->fn);
718 }
719
720 if(mheader->mapi_unregister)
721 mheader->mapi_unregister();
722
723 if(mheader->mapi_cap_list)
724 {
725 mapi_cap_list_av2 *m;
726 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
727 {
728 struct CapabilityIndex *idx;
729
730 switch(m->cap_index)
731 {
732 case MAPI_CAP_CLIENT:
733 idx = cli_capindex;
734 break;
735 case MAPI_CAP_SERVER:
736 idx = serv_capindex;
737 break;
738 default:
739 sendto_realops_snomask(SNO_GENERAL, L_ALL,
740 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
741 m->cap_index, m->cap_name, modlist[modindex]->name);
742 ilog(L_MAIN,
743 "Unknown/unsupported CAP index found of type %d on capability %s when unloading %s",
744 m->cap_index, m->cap_name, modlist[modindex]->name);
745 continue;
746 }
747
748 capability_orphan(idx, m->cap_name);
749 }
750 }
751 }
212380e3
AC
752 default:
753 sendto_realops_snomask(SNO_GENERAL, L_ALL,
754 "Unknown/unsupported MAPI version %d when unloading %s!",
755 modlist[modindex]->mapi_version, modlist[modindex]->name);
756 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
757 modlist[modindex]->mapi_version, modlist[modindex]->name);
758 break;
759 }
760
f272e7ab 761 lt_dlclose(modlist[modindex]->address);
212380e3 762
637c4932 763 rb_free(modlist[modindex]->name);
55d5f797 764 rb_free(modlist[modindex]);
f54e1a8f 765 memmove(&modlist[modindex], &modlist[modindex + 1],
1e170010 766 sizeof(struct module *) * ((num_mods - 1) - modindex));
212380e3
AC
767
768 if(num_mods != 0)
769 num_mods--;
770
771 if(warn == 1)
772 {
773 ilog(L_MAIN, "Module %s unloaded", name);
774 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
775 }
776
777 return 0;
778}
779
780
781/*
782 * load_a_module()
783 *
784 * inputs - path name of module, int to notice, int of core
785 * output - -1 if error 0 if success
786 * side effects - loads a module if successful
787 */
788int
789load_a_module(const char *path, int warn, int core)
790{
f272e7ab 791 lt_dlhandle tmpptr;
212380e3 792 char *mod_basename;
8e9c6a75 793 const char *ver, *description = NULL;
c63aeb44 794 int origin = 0;
212380e3
AC
795
796 int *mapi_version;
797
b7a689d1 798 mod_basename = rb_basename(path);
212380e3 799
d76258f5 800 tmpptr = lt_dlopen(path);
212380e3
AC
801
802 if(tmpptr == NULL)
803 {
f272e7ab 804 const char *err = lt_dlerror();
212380e3
AC
805
806 sendto_realops_snomask(SNO_GENERAL, L_ALL,
807 "Error loading module %s: %s", mod_basename, err);
808 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
637c4932 809 rb_free(mod_basename);
212380e3
AC
810 return -1;
811 }
812
813
814 /*
815 * _mheader is actually a struct mapi_mheader_*, but mapi_version
816 * is always the first member of this structure, so we treate it
817 * as a single int in order to determine the API version.
818 * -larne.
819 */
f272e7ab 820 mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "_mheader");
212380e3 821 if((mapi_version == NULL
f272e7ab 822 && (mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "__mheader")) == NULL)
212380e3
AC
823 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
824 {
825 sendto_realops_snomask(SNO_GENERAL, L_ALL,
826 "Data format error: module %s has no MAPI header.",
827 mod_basename);
828 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
f272e7ab 829 (void) lt_dlclose(tmpptr);
637c4932 830 rb_free(mod_basename);
212380e3
AC
831 return -1;
832 }
833
834 switch (MAPI_VERSION(*mapi_version))
835 {
836 case 1:
837 {
29c92cf9 838 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *)(void *)mapi_version; /* see above */
212380e3
AC
839 if(mheader->mapi_register && (mheader->mapi_register() == -1))
840 {
841 ilog(L_MAIN, "Module %s indicated failure during load.",
842 mod_basename);
843 sendto_realops_snomask(SNO_GENERAL, L_ALL,
844 "Module %s indicated failure during load.",
845 mod_basename);
f272e7ab 846 lt_dlclose(tmpptr);
637c4932 847 rb_free(mod_basename);
212380e3
AC
848 return -1;
849 }
850 if(mheader->mapi_command_list)
851 {
852 struct Message **m;
853 for (m = mheader->mapi_command_list; *m; ++m)
854 mod_add_cmd(*m);
855 }
856
857 if(mheader->mapi_hook_list)
858 {
859 mapi_hlist_av1 *m;
860 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
861 *m->hapi_id = register_hook(m->hapi_name);
862 }
863
864 if(mheader->mapi_hfn_list)
865 {
866 mapi_hfn_list_av1 *m;
867 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
868 add_hook(m->hapi_name, m->fn);
869 }
870
871 ver = mheader->mapi_module_version;
872 break;
873 }
8e9c6a75
EM
874 case 2:
875 {
876 struct mapi_mheader_av2 *mheader = (struct mapi_mheader_av2 *)(void *)mapi_version; /* see above */
212380e3 877
8e9c6a75
EM
878 /* XXX duplicated code :( */
879 if(mheader->mapi_register && (mheader->mapi_register() == -1))
880 {
881 ilog(L_MAIN, "Module %s indicated failure during load.",
882 mod_basename);
883 sendto_realops_snomask(SNO_GENERAL, L_ALL,
884 "Module %s indicated failure during load.",
885 mod_basename);
886 lt_dlclose(tmpptr);
887 rb_free(mod_basename);
888 return -1;
889 }
890 if(mheader->mapi_command_list)
891 {
892 struct Message **m;
893 for (m = mheader->mapi_command_list; *m; ++m)
894 mod_add_cmd(*m);
895 }
896
897 if(mheader->mapi_hook_list)
898 {
899 mapi_hlist_av1 *m;
900 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
901 *m->hapi_id = register_hook(m->hapi_name);
902 }
903
904 if(mheader->mapi_hfn_list)
905 {
906 mapi_hfn_list_av1 *m;
907 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
908 add_hook(m->hapi_name, m->fn);
909 }
910
911 /* New in MAPI v2 - version replacement */
912 ver = mheader->mapi_module_version ? mheader->mapi_module_version : ircd_version;
913 description = mheader->mapi_module_description;
c63aeb44 914 origin = mheader->mapi_origin;
8e9c6a75
EM
915
916 if(mheader->mapi_cap_list)
917 {
918 mapi_cap_list_av2 *m;
919 for (m = mheader->mapi_cap_list; m->cap_name; ++m)
920 {
921 struct CapabilityIndex *idx;
922 int result;
923
924 switch(m->cap_index)
925 {
926 case MAPI_CAP_CLIENT:
927 idx = cli_capindex;
928 break;
929 case MAPI_CAP_SERVER:
930 idx = serv_capindex;
931 break;
932 default:
933 sendto_realops_snomask(SNO_GENERAL, L_ALL,
934 "Unknown/unsupported CAP index found of type %d on capability %s when loading %s",
935 m->cap_index, m->cap_name, mod_basename);
936 ilog(L_MAIN,
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 continue;
940 }
941
942 result = capability_put(idx, m->cap_name, m->cap_ownerdata);
943 if (m->cap_id != NULL)
944 *(m->cap_id) = result;
945 }
946 }
947 }
0e5bf029
EM
948
949 break;
212380e3
AC
950 default:
951 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
952 mod_basename, MAPI_VERSION(*mapi_version));
953 sendto_realops_snomask(SNO_GENERAL, L_ALL,
954 "Module %s has unknown/unsupported MAPI version %d.",
955 mod_basename, *mapi_version);
f272e7ab 956 lt_dlclose(tmpptr);
637c4932 957 rb_free(mod_basename);
212380e3
AC
958 return -1;
959 }
960
961 if(ver == NULL)
962 ver = unknown_ver;
963
8e9c6a75
EM
964 if(description == NULL)
965 description = unknown_description;
966
212380e3
AC
967 increase_modlist();
968
eddc2ab6 969 modlist[num_mods] = rb_malloc(sizeof(struct module));
212380e3
AC
970 modlist[num_mods]->address = tmpptr;
971 modlist[num_mods]->version = ver;
0eb7d9c0 972 modlist[num_mods]->description = description;
212380e3 973 modlist[num_mods]->core = core;
47a03750 974 modlist[num_mods]->name = rb_strdup(mod_basename);
212380e3
AC
975 modlist[num_mods]->mapi_header = mapi_version;
976 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
c63aeb44 977 modlist[num_mods]->origin = origin;
212380e3
AC
978 num_mods++;
979
980 if(warn == 1)
981 {
c63aeb44
EM
982 const char *o;
983
984 switch(origin)
985 {
986 case MAPI_ORIGIN_EXTERNAL:
987 o = "external";
988 break;
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}