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