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