]> jfr.im git - solanum.git/blob - ircd/modules.c
Remove libratbox's snprintf.c, update related ircd code
[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 * $Id: modules.c 3161 2007-01-25 07:23:01Z nenolod $
25 */
26
27 #include "stdinc.h"
28 #include "modules.h"
29 #include "logger.h"
30 #include "ircd.h"
31 #include "client.h"
32 #include "send.h"
33 #include "s_conf.h"
34 #include "s_newconf.h"
35 #include "numeric.h"
36 #include "parse.h"
37 #include "ircd_defs.h"
38 #include "match.h"
39 #include "s_serv.h"
40
41 #include <ltdl.h>
42
43 struct module **modlist = NULL;
44
45 static const char *core_module_table[] = {
46 "m_ban",
47 "m_die",
48 "m_error",
49 "m_join",
50 "m_kick",
51 "m_kill",
52 "m_message",
53 "m_mode",
54 "m_nick",
55 "m_part",
56 "m_quit",
57 "m_server",
58 "m_squit",
59 NULL
60 };
61
62 #define MODS_INCREMENT 10
63 int num_mods = 0;
64 int max_mods = MODS_INCREMENT;
65
66 static rb_dlink_list mod_paths;
67
68 static int mo_modload(struct Client *, struct Client *, int, const char **);
69 static int mo_modlist(struct Client *, struct Client *, int, const char **);
70 static int mo_modreload(struct Client *, struct Client *, int, const char **);
71 static int mo_modunload(struct Client *, struct Client *, int, const char **);
72 static int mo_modrestart(struct Client *, struct Client *, int, const char **);
73
74 static int me_modload(struct Client *, struct Client *, int, const char **);
75 static int me_modlist(struct Client *, struct Client *, int, const char **);
76 static int me_modreload(struct Client *, struct Client *, int, const char **);
77 static int me_modunload(struct Client *, struct Client *, int, const char **);
78 static int me_modrestart(struct Client *, struct Client *, int, const char **);
79
80 static int do_modload(struct Client *, const char *);
81 static int do_modunload(struct Client *, const char *);
82 static int do_modreload(struct Client *, const char *);
83 static int do_modlist(struct Client *, const char *);
84 static int do_modrestart(struct Client *);
85
86 struct Message modload_msgtab = {
87 "MODLOAD", 0, 0, 0, MFLG_SLOW,
88 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modload, 2}, {mo_modload, 2}}
89 };
90
91 struct Message modunload_msgtab = {
92 "MODUNLOAD", 0, 0, 0, MFLG_SLOW,
93 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modunload, 2}, {mo_modunload, 2}}
94 };
95
96 struct Message modreload_msgtab = {
97 "MODRELOAD", 0, 0, 0, MFLG_SLOW,
98 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modreload, 2}, {mo_modreload, 2}}
99 };
100
101 struct Message modlist_msgtab = {
102 "MODLIST", 0, 0, 0, MFLG_SLOW,
103 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modlist, 0}, {mo_modlist, 0}}
104 };
105
106 struct Message modrestart_msgtab = {
107 "MODRESTART", 0, 0, 0, MFLG_SLOW,
108 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_modrestart, 0}, {mo_modrestart, 0}}
109 };
110
111 void
112 modules_init(void)
113 {
114 if(lt_dlinit())
115 {
116 ilog(L_MAIN, "lt_dlinit failed");
117 exit(0);
118 }
119
120 mod_add_cmd(&modload_msgtab);
121 mod_add_cmd(&modunload_msgtab);
122 mod_add_cmd(&modreload_msgtab);
123 mod_add_cmd(&modlist_msgtab);
124 mod_add_cmd(&modrestart_msgtab);
125
126 /* Add the default paths we look in to the module system --nenolod */
127 mod_add_path(MODPATH);
128 mod_add_path(AUTOMODPATH);
129 }
130
131 /* mod_find_path()
132 *
133 * input - path
134 * output - none
135 * side effects - returns a module path from path
136 */
137 static char *
138 mod_find_path(const char *path)
139 {
140 rb_dlink_node *ptr;
141 char *mpath;
142
143 RB_DLINK_FOREACH(ptr, mod_paths.head)
144 {
145 mpath = ptr->data;
146
147 if(!strcmp(path, mpath))
148 return mpath;
149 }
150
151 return NULL;
152 }
153
154 /* mod_add_path
155 *
156 * input - path
157 * ouput -
158 * side effects - adds path to list
159 */
160 void
161 mod_add_path(const char *path)
162 {
163 char *pathst;
164
165 if(mod_find_path(path))
166 return;
167
168 pathst = rb_strdup(path);
169 rb_dlinkAddAlloc(pathst, &mod_paths);
170 }
171
172 /* mod_clear_paths()
173 *
174 * input -
175 * output -
176 * side effects - clear the lists of paths
177 */
178 void
179 mod_clear_paths(void)
180 {
181 rb_dlink_node *ptr, *next_ptr;
182
183 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
184 {
185 rb_free(ptr->data);
186 rb_free_rb_dlink_node(ptr);
187 }
188
189 mod_paths.head = mod_paths.tail = NULL;
190 mod_paths.length = 0;
191 }
192
193 /* findmodule_byname
194 *
195 * input -
196 * output -
197 * side effects -
198 */
199
200 int
201 findmodule_byname(const char *name)
202 {
203 int i;
204
205 for (i = 0; i < num_mods; i++)
206 {
207 if(!irccmp(modlist[i]->name, name))
208 return i;
209 }
210 return -1;
211 }
212
213 /* load_all_modules()
214 *
215 * input -
216 * output -
217 * side effects -
218 */
219 void
220 load_all_modules(int warn)
221 {
222 DIR *system_module_dir = NULL;
223 struct dirent *ldirent = NULL;
224 char module_fq_name[PATH_MAX + 1];
225 int len;
226
227 modules_init();
228
229 modlist = (struct module **) rb_malloc(sizeof(struct module *) * (MODS_INCREMENT));
230
231 max_mods = MODS_INCREMENT;
232
233 system_module_dir = opendir(AUTOMODPATH);
234
235 if(system_module_dir == NULL)
236 {
237 ilog(L_MAIN, "Could not load modules from %s: %s", AUTOMODPATH, strerror(errno));
238 return;
239 }
240
241 while ((ldirent = readdir(system_module_dir)) != NULL)
242 {
243 len = strlen(ldirent->d_name);
244 if((len > 3) && !strcmp(ldirent->d_name+len-3, ".la"))
245 {
246 (void) snprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", AUTOMODPATH, ldirent->d_name);
247 (void) load_a_module(module_fq_name, warn, 0);
248 }
249
250 }
251 (void) closedir(system_module_dir);
252 }
253
254 /* load_core_modules()
255 *
256 * input -
257 * output -
258 * side effects - core modules are loaded, if any fail, kill ircd
259 */
260 void
261 load_core_modules(int warn)
262 {
263 char module_name[PATH_MAX];
264 int i;
265
266
267 for (i = 0; core_module_table[i]; i++)
268 {
269 snprintf(module_name, sizeof(module_name), "%s/%s%s", MODPATH,
270 core_module_table[i], ".la");
271
272 if(load_a_module(module_name, warn, 1) == -1)
273 {
274 ilog(L_MAIN,
275 "Error loading core module %s%s: terminating ircd",
276 core_module_table[i], ".la");
277 exit(0);
278 }
279 }
280 }
281
282 /* load_one_module()
283 *
284 * input -
285 * output -
286 * side effects -
287 */
288 int
289 load_one_module(const char *path, int coremodule)
290 {
291 char modpath[PATH_MAX];
292 rb_dlink_node *pathst;
293 const char *mpath;
294
295 struct stat statbuf;
296
297 if (server_state_foreground == 1)
298 inotice("loading module %s ...", path);
299
300 RB_DLINK_FOREACH(pathst, mod_paths.head)
301 {
302 mpath = pathst->data;
303
304 snprintf(modpath, sizeof(modpath), "%s/%s", mpath, path);
305 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
306 {
307 if(stat(modpath, &statbuf) == 0)
308 {
309 if(S_ISREG(statbuf.st_mode))
310 {
311 /* Regular files only please */
312 if(coremodule)
313 return load_a_module(modpath, 1, 1);
314 else
315 return load_a_module(modpath, 1, 0);
316 }
317 }
318
319 }
320 }
321
322 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
323 return -1;
324 }
325
326
327 /* load a module .. */
328 static int
329 mo_modload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
330 {
331 if(!IsOperAdmin(source_p))
332 {
333 sendto_one(source_p, form_str(ERR_NOPRIVS),
334 me.name, source_p->name, "admin");
335 return 0;
336 }
337
338 if(parc > 2)
339 {
340 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
341 "ENCAP %s MODLOAD %s", parv[2], parv[1]);
342 if (match(parv[2], me.name) == 0)
343 return 0;
344 }
345
346 return do_modload(source_p, parv[1]);
347 }
348
349 static int
350 me_modload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
351 {
352 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
353 {
354 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
355 "to load modules on this server.");
356 return 0;
357 }
358
359 return do_modload(source_p, parv[1]);
360 }
361
362 static int
363 do_modload(struct Client *source_p, const char *module)
364 {
365 char *m_bn = rb_basename(module);
366
367 if(findmodule_byname(m_bn) != -1)
368 {
369 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
370 rb_free(m_bn);
371 return 0;
372 }
373
374 load_one_module(module, 0);
375
376 rb_free(m_bn);
377
378 return 0;
379 }
380
381
382 /* unload a module .. */
383 static int
384 mo_modunload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
385 {
386 if(!IsOperAdmin(source_p))
387 {
388 sendto_one(source_p, form_str(ERR_NOPRIVS),
389 me.name, source_p->name, "admin");
390 return 0;
391 }
392
393 if(parc > 2)
394 {
395 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
396 "ENCAP %s MODUNLOAD %s", parv[2], parv[1]);
397 if (match(parv[2], me.name) == 0)
398 return 0;
399 }
400
401 return do_modunload(source_p, parv[1]);
402 }
403
404 static int
405 me_modunload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
406 {
407 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
408 {
409 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
410 "to load modules on this server.");
411 return 0;
412 }
413
414 return do_modunload(source_p, parv[1]);
415 }
416
417 static int
418 do_modunload(struct Client *source_p, const char *module)
419 {
420 int modindex;
421 char *m_bn = rb_basename(module);
422
423 if((modindex = findmodule_byname(m_bn)) == -1)
424 {
425 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
426 rb_free(m_bn);
427 return 0;
428 }
429
430 if(modlist[modindex]->core == 1)
431 {
432 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
433 rb_free(m_bn);
434 return 0;
435 }
436
437 if(unload_one_module(m_bn, 1) == -1)
438 {
439 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
440 }
441
442 rb_free(m_bn);
443 return 0;
444 }
445
446 /* unload and load in one! */
447 static int
448 mo_modreload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
449 {
450 if(!IsOperAdmin(source_p))
451 {
452 sendto_one(source_p, form_str(ERR_NOPRIVS),
453 me.name, source_p->name, "admin");
454 return 0;
455 }
456
457 if(parc > 2)
458 {
459 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
460 "ENCAP %s MODRELOAD %s", parv[2], parv[1]);
461 if (match(parv[2], me.name) == 0)
462 return 0;
463 }
464
465 return do_modreload(source_p, parv[1]);
466 }
467
468 static int
469 me_modreload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
470 {
471 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
472 {
473 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
474 "to load modules on this server.");
475 return 0;
476 }
477
478 return do_modreload(source_p, parv[1]);
479 }
480
481 static int
482 do_modreload(struct Client *source_p, const char *module)
483 {
484 int modindex;
485 int check_core;
486 char *m_bn = rb_basename(module);
487
488 if((modindex = findmodule_byname(m_bn)) == -1)
489 {
490 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
491 rb_free(m_bn);
492 return 0;
493 }
494
495 check_core = modlist[modindex]->core;
496
497 if(unload_one_module(m_bn, 1) == -1)
498 {
499 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
500 rb_free(m_bn);
501 return 0;
502 }
503
504 if((load_one_module(m_bn, check_core) == -1) && check_core)
505 {
506 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
507 "Error reloading core module: %s: terminating ircd", m_bn);
508 ilog(L_MAIN, "Error loading core module %s: terminating ircd", m_bn);
509 exit(0);
510 }
511
512 rb_free(m_bn);
513 return 0;
514 }
515
516 /* list modules .. */
517 static int
518 mo_modlist(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
519 {
520 if(!IsOperAdmin(source_p))
521 {
522 sendto_one(source_p, form_str(ERR_NOPRIVS),
523 me.name, source_p->name, "admin");
524 return 0;
525 }
526
527 if(parc > 2)
528 {
529 sendto_match_servs(source_p, parv[2], CAP_ENCAP, NOCAPS,
530 "ENCAP %s MODLIST %s", parv[2], parv[1]);
531 if (match(parv[2], me.name) == 0)
532 return 0;
533 }
534
535 return do_modlist(source_p, parc > 1 ? parv[1] : 0);
536 }
537
538 static int
539 me_modlist(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
540 {
541 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
542 {
543 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
544 "to load modules on this server.");
545 return 0;
546 }
547
548 return do_modlist(source_p, parv[1]);
549 }
550
551 static int
552 do_modlist(struct Client *source_p, const char *pattern)
553 {
554 int i;
555
556 for (i = 0; i < num_mods; i++)
557 {
558 if(pattern)
559 {
560 if(match(pattern, modlist[i]->name))
561 {
562 sendto_one(source_p, form_str(RPL_MODLIST),
563 me.name, source_p->name,
564 modlist[i]->name,
565 (unsigned long)(uintptr_t)modlist[i]->address,
566 modlist[i]->version, modlist[i]->core ? "(core)" : "");
567 }
568 }
569 else
570 {
571 sendto_one(source_p, form_str(RPL_MODLIST),
572 me.name, source_p->name, modlist[i]->name,
573 (unsigned long)(uintptr_t)modlist[i]->address, modlist[i]->version,
574 modlist[i]->core ? "(core)" : "");
575 }
576 }
577
578 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
579 return 0;
580 }
581
582 /* unload and reload all modules */
583 static int
584 mo_modrestart(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
585 {
586 if(!IsOperAdmin(source_p))
587 {
588 sendto_one(source_p, form_str(ERR_NOPRIVS),
589 me.name, source_p->name, "admin");
590 return 0;
591 }
592
593 if(parc > 1)
594 {
595 sendto_match_servs(source_p, parv[1], CAP_ENCAP, NOCAPS,
596 "ENCAP %s MODRESTART", parv[1]);
597 if (match(parv[1], me.name) == 0)
598 return 0;
599 }
600
601 return do_modrestart(source_p);
602 }
603
604 static int
605 me_modrestart(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
606 {
607 if(!find_shared_conf(source_p->username, source_p->host, source_p->servptr->name, SHARED_MODULE))
608 {
609 sendto_one_notice(source_p, ":*** You do not have an appropriate shared block "
610 "to load modules on this server.");
611 return 0;
612 }
613
614 return do_modrestart(source_p);
615 }
616
617 static int
618 do_modrestart(struct Client *source_p)
619 {
620 int modnum;
621
622 sendto_one_notice(source_p, ":Reloading all modules");
623
624 modnum = num_mods;
625 while (num_mods)
626 unload_one_module(modlist[0]->name, 0);
627
628 load_all_modules(0);
629 load_core_modules(0);
630 rehash(0);
631
632 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
633 "Module Restart: %d modules unloaded, %d modules loaded",
634 modnum, num_mods);
635 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
636 return 0;
637 }
638
639
640 static void increase_modlist(void);
641
642 #define MODS_INCREMENT 10
643
644 static char unknown_ver[] = "<unknown>";
645
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 */
653 int
654 unload_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
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
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 }
698 default:
699 sendto_realops_snomask(SNO_GENERAL, L_ALL,
700 "Unknown/unsupported MAPI version %d when unloading %s!",
701 modlist[modindex]->mapi_version, modlist[modindex]->name);
702 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
703 modlist[modindex]->mapi_version, modlist[modindex]->name);
704 break;
705 }
706
707 lt_dlclose(modlist[modindex]->address);
708
709 rb_free(modlist[modindex]->name);
710 rb_free(modlist[modindex]);
711 memmove(&modlist[modindex], &modlist[modindex + 1],
712 sizeof(struct module *) * ((num_mods - 1) - modindex));
713
714 if(num_mods != 0)
715 num_mods--;
716
717 if(warn == 1)
718 {
719 ilog(L_MAIN, "Module %s unloaded", name);
720 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
721 }
722
723 return 0;
724 }
725
726
727 /*
728 * load_a_module()
729 *
730 * inputs - path name of module, int to notice, int of core
731 * output - -1 if error 0 if success
732 * side effects - loads a module if successful
733 */
734 int
735 load_a_module(const char *path, int warn, int core)
736 {
737 lt_dlhandle tmpptr;
738 char *mod_basename;
739 const char *ver;
740
741 int *mapi_version;
742
743 mod_basename = rb_basename(path);
744
745 tmpptr = lt_dlopen(path);
746
747 if(tmpptr == NULL)
748 {
749 const char *err = lt_dlerror();
750
751 sendto_realops_snomask(SNO_GENERAL, L_ALL,
752 "Error loading module %s: %s", mod_basename, err);
753 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
754 rb_free(mod_basename);
755 return -1;
756 }
757
758
759 /*
760 * _mheader is actually a struct mapi_mheader_*, but mapi_version
761 * is always the first member of this structure, so we treate it
762 * as a single int in order to determine the API version.
763 * -larne.
764 */
765 mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "_mheader");
766 if((mapi_version == NULL
767 && (mapi_version = (int *) (uintptr_t) lt_dlsym(tmpptr, "__mheader")) == NULL)
768 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
769 {
770 sendto_realops_snomask(SNO_GENERAL, L_ALL,
771 "Data format error: module %s has no MAPI header.",
772 mod_basename);
773 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
774 (void) lt_dlclose(tmpptr);
775 rb_free(mod_basename);
776 return -1;
777 }
778
779 switch (MAPI_VERSION(*mapi_version))
780 {
781 case 1:
782 {
783 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *)(void *)mapi_version; /* see above */
784 if(mheader->mapi_register && (mheader->mapi_register() == -1))
785 {
786 ilog(L_MAIN, "Module %s indicated failure during load.",
787 mod_basename);
788 sendto_realops_snomask(SNO_GENERAL, L_ALL,
789 "Module %s indicated failure during load.",
790 mod_basename);
791 lt_dlclose(tmpptr);
792 rb_free(mod_basename);
793 return -1;
794 }
795 if(mheader->mapi_command_list)
796 {
797 struct Message **m;
798 for (m = mheader->mapi_command_list; *m; ++m)
799 mod_add_cmd(*m);
800 }
801
802 if(mheader->mapi_hook_list)
803 {
804 mapi_hlist_av1 *m;
805 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
806 *m->hapi_id = register_hook(m->hapi_name);
807 }
808
809 if(mheader->mapi_hfn_list)
810 {
811 mapi_hfn_list_av1 *m;
812 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
813 add_hook(m->hapi_name, m->fn);
814 }
815
816 ver = mheader->mapi_module_version;
817 break;
818 }
819
820 default:
821 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
822 mod_basename, MAPI_VERSION(*mapi_version));
823 sendto_realops_snomask(SNO_GENERAL, L_ALL,
824 "Module %s has unknown/unsupported MAPI version %d.",
825 mod_basename, *mapi_version);
826 lt_dlclose(tmpptr);
827 rb_free(mod_basename);
828 return -1;
829 }
830
831 if(ver == NULL)
832 ver = unknown_ver;
833
834 increase_modlist();
835
836 modlist[num_mods] = rb_malloc(sizeof(struct module));
837 modlist[num_mods]->address = tmpptr;
838 modlist[num_mods]->version = ver;
839 modlist[num_mods]->core = core;
840 modlist[num_mods]->name = rb_strdup(mod_basename);
841 modlist[num_mods]->mapi_header = mapi_version;
842 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
843 num_mods++;
844
845 if(warn == 1)
846 {
847 sendto_realops_snomask(SNO_GENERAL, L_ALL,
848 "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
849 mod_basename, ver, MAPI_VERSION(*mapi_version),
850 (unsigned long) tmpptr);
851 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
852 mod_basename, ver, MAPI_VERSION(*mapi_version), (unsigned long) tmpptr);
853 }
854 rb_free(mod_basename);
855 return 0;
856 }
857
858 /*
859 * increase_modlist
860 *
861 * inputs - NONE
862 * output - NONE
863 * side effects - expand the size of modlist if necessary
864 */
865 static void
866 increase_modlist(void)
867 {
868 struct module **new_modlist = NULL;
869
870 if((num_mods + 1) < max_mods)
871 return;
872
873 new_modlist = (struct module **) rb_malloc(sizeof(struct module *) *
874 (max_mods + MODS_INCREMENT));
875 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module *) * num_mods);
876
877 rb_free(modlist);
878 modlist = new_modlist;
879 max_mods += MODS_INCREMENT;
880 }