]> jfr.im git - irc/rqf/shadowircd.git/blob - src/modules.c
Make charybdis not search m_sjoin as its a core module
[irc/rqf/shadowircd.git] / src / 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
29
30 #include "modules.h"
31 #include "logger.h"
32 #include "ircd.h"
33 #include "client.h"
34 #include "send.h"
35 #include "s_conf.h"
36 #include "s_newconf.h"
37 #include "numeric.h"
38 #include "parse.h"
39 #include "ircd_defs.h"
40 #include "irc_string.h"
41 #include "sprintf_irc.h"
42
43
44
45 /* -TimeMr14C:
46 * I have moved the dl* function definitions and
47 * the two functions (load_a_module / unload_a_module) to the
48 * file dynlink.c
49 * And also made the necessary changes to those functions
50 * to comply with shl_load and friends.
51 * In this file, to keep consistency with the makefile,
52 * I added the ability to load *.sl files, too.
53 * 27/02/2002
54 */
55
56 #ifndef STATIC_MODULES
57
58 struct module **modlist = NULL;
59
60 static const char *core_module_table[] = {
61 "m_die",
62 "m_error",
63 "m_join",
64 "m_kick",
65 "m_kill",
66 "m_message",
67 "m_mode",
68 "m_nick",
69 "m_part",
70 "m_quit",
71 "m_server",
72 "m_squit",
73 NULL
74 };
75
76 #define MODS_INCREMENT 10
77 int num_mods = 0;
78 int max_mods = MODS_INCREMENT;
79
80 static rb_dlink_list mod_paths;
81
82 static int mo_modload(struct Client *, struct Client *, int, const char **);
83 static int mo_modlist(struct Client *, struct Client *, int, const char **);
84 static int mo_modreload(struct Client *, struct Client *, int, const char **);
85 static int mo_modunload(struct Client *, struct Client *, int, const char **);
86 static int mo_modrestart(struct Client *, struct Client *, int, const char **);
87
88 struct Message modload_msgtab = {
89 "MODLOAD", 0, 0, 0, MFLG_SLOW,
90 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modload, 2}}
91 };
92
93 struct Message modunload_msgtab = {
94 "MODUNLOAD", 0, 0, 0, MFLG_SLOW,
95 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modunload, 2}}
96 };
97
98 struct Message modreload_msgtab = {
99 "MODRELOAD", 0, 0, 0, MFLG_SLOW,
100 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modreload, 2}}
101 };
102
103 struct Message modlist_msgtab = {
104 "MODLIST", 0, 0, 0, MFLG_SLOW,
105 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modlist, 0}}
106 };
107
108 struct Message modrestart_msgtab = {
109 "MODRESTART", 0, 0, 0, MFLG_SLOW,
110 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modrestart, 0}}
111 };
112
113 extern struct Message error_msgtab;
114
115 void
116 modules_init(void)
117 {
118 mod_add_cmd(&modload_msgtab);
119 mod_add_cmd(&modunload_msgtab);
120 mod_add_cmd(&modreload_msgtab);
121 mod_add_cmd(&modlist_msgtab);
122 mod_add_cmd(&modrestart_msgtab);
123
124 /* Add the default paths we look in to the module system --nenolod */
125 mod_add_path(MODPATH);
126 mod_add_path(AUTOMODPATH);
127 }
128
129 /* mod_find_path()
130 *
131 * input - path
132 * output - none
133 * side effects - returns a module path from path
134 */
135 static struct module_path *
136 mod_find_path(const char *path)
137 {
138 rb_dlink_node *ptr;
139 struct module_path *mpath;
140
141 RB_DLINK_FOREACH(ptr, mod_paths.head)
142 {
143 mpath = ptr->data;
144
145 if(!strcmp(path, mpath->path))
146 return mpath;
147 }
148
149 return NULL;
150 }
151
152 /* mod_add_path
153 *
154 * input - path
155 * ouput -
156 * side effects - adds path to list
157 */
158 void
159 mod_add_path(const char *path)
160 {
161 struct module_path *pathst;
162
163 if(mod_find_path(path))
164 return;
165
166 pathst = rb_malloc(sizeof(struct module_path));
167
168 strcpy(pathst->path, 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 /* irc_basename
194 *
195 * input -
196 * output -
197 * side effects -
198 */
199 char *
200 irc_basename(const char *path)
201 {
202 char *mod_basename = rb_malloc(strlen(path) + 1);
203 const char *s;
204
205 if(!(s = strrchr(path, '/')))
206 s = path;
207 else
208 s++;
209
210 (void) strcpy(mod_basename, s);
211 return mod_basename;
212 }
213
214 /* findmodule_byname
215 *
216 * input -
217 * output -
218 * side effects -
219 */
220
221 int
222 findmodule_byname(const char *name)
223 {
224 int i;
225
226 for (i = 0; i < num_mods; i++)
227 {
228 if(!irccmp(modlist[i]->name, name))
229 return i;
230 }
231 return -1;
232 }
233
234 /* load_all_modules()
235 *
236 * input -
237 * output -
238 * side effects -
239 */
240 void
241 load_all_modules(int warn)
242 {
243 DIR *system_module_dir = NULL;
244 struct dirent *ldirent = NULL;
245 char module_fq_name[PATH_MAX + 1];
246 int len;
247
248 modules_init();
249
250 modlist = (struct module **) rb_malloc(sizeof(struct module) * (MODS_INCREMENT));
251
252 max_mods = MODS_INCREMENT;
253
254 system_module_dir = opendir(AUTOMODPATH);
255
256 if(system_module_dir == NULL)
257 {
258 ilog(L_MAIN, "Could not load modules from %s: %s", AUTOMODPATH, strerror(errno));
259 return;
260 }
261
262 while ((ldirent = readdir(system_module_dir)) != NULL)
263 {
264 len = strlen(ldirent->d_name);
265 if((len > 3) && !strcmp(ldirent->d_name+len-3, SHARED_SUFFIX))
266 {
267 (void) rb_snprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", AUTOMODPATH, ldirent->d_name);
268 (void) load_a_module(module_fq_name, warn, 0);
269 }
270
271 }
272 (void) closedir(system_module_dir);
273 }
274
275 /* load_core_modules()
276 *
277 * input -
278 * output -
279 * side effects - core modules are loaded, if any fail, kill ircd
280 */
281 void
282 load_core_modules(int warn)
283 {
284 char module_name[MAXPATHLEN];
285 int i;
286
287
288 for (i = 0; core_module_table[i]; i++)
289 {
290 rb_snprintf(module_name, sizeof(module_name), "%s/%s%s", MODPATH,
291 core_module_table[i], SHARED_SUFFIX);
292
293 if(load_a_module(module_name, warn, 1) == -1)
294 {
295 ilog(L_MAIN,
296 "Error loading core module %s%s: terminating ircd",
297 core_module_table[i], SHARED_SUFFIX);
298 exit(0);
299 }
300 }
301 }
302
303 /* load_one_module()
304 *
305 * input -
306 * output -
307 * side effects -
308 */
309 int
310 load_one_module(const char *path, int coremodule)
311 {
312 char modpath[MAXPATHLEN];
313 rb_dlink_node *pathst;
314 struct module_path *mpath;
315
316 struct stat statbuf;
317
318 if (server_state_foreground == 1)
319 inotice("loading module %s ...", path);
320
321 RB_DLINK_FOREACH(pathst, mod_paths.head)
322 {
323 mpath = pathst->data;
324
325 rb_snprintf(modpath, sizeof(modpath), "%s/%s", mpath->path, path);
326 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
327 {
328 if(stat(modpath, &statbuf) == 0)
329 {
330 if(S_ISREG(statbuf.st_mode))
331 {
332 /* Regular files only please */
333 if(coremodule)
334 return load_a_module(modpath, 1, 1);
335 else
336 return load_a_module(modpath, 1, 0);
337 }
338 }
339
340 }
341 }
342
343 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
344 return -1;
345 }
346
347
348 /* load a module .. */
349 static int
350 mo_modload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
351 {
352 char *m_bn;
353
354 if(!IsOperAdmin(source_p))
355 {
356 sendto_one(source_p, form_str(ERR_NOPRIVS),
357 me.name, source_p->name, "admin");
358 return 0;
359 }
360
361 m_bn = irc_basename(parv[1]);
362
363 if(findmodule_byname(m_bn) != -1)
364 {
365 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
366 rb_free(m_bn);
367 return 0;
368 }
369
370 load_one_module(parv[1], 0);
371
372 rb_free(m_bn);
373
374 return 0;
375 }
376
377
378 /* unload a module .. */
379 static int
380 mo_modunload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
381 {
382 char *m_bn;
383 int modindex;
384
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
392 m_bn = irc_basename(parv[1]);
393
394 if((modindex = findmodule_byname(m_bn)) == -1)
395 {
396 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
397 rb_free(m_bn);
398 return 0;
399 }
400
401 if(modlist[modindex]->core == 1)
402 {
403 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
404 rb_free(m_bn);
405 return 0;
406 }
407
408 if(unload_one_module(m_bn, 1) == -1)
409 {
410 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
411 }
412
413 rb_free(m_bn);
414 return 0;
415 }
416
417 /* unload and load in one! */
418 static int
419 mo_modreload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
420 {
421 char *m_bn;
422 int modindex;
423 int check_core;
424
425 if(!IsOperAdmin(source_p))
426 {
427 sendto_one(source_p, form_str(ERR_NOPRIVS),
428 me.name, source_p->name, "admin");
429 return 0;
430 }
431
432 m_bn = irc_basename(parv[1]);
433
434 if((modindex = findmodule_byname(m_bn)) == -1)
435 {
436 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
437 rb_free(m_bn);
438 return 0;
439 }
440
441 check_core = modlist[modindex]->core;
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 rb_free(m_bn);
447 return 0;
448 }
449
450 if((load_one_module(parv[1], check_core) == -1) && check_core)
451 {
452 sendto_realops_snomask(SNO_GENERAL, L_ALL,
453 "Error reloading core module: %s: terminating ircd", parv[1]);
454 ilog(L_MAIN, "Error loading core module %s: terminating ircd", parv[1]);
455 exit(0);
456 }
457
458 rb_free(m_bn);
459 return 0;
460 }
461
462 /* list modules .. */
463 static int
464 mo_modlist(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
465 {
466 int i;
467
468 if(!IsOperAdmin(source_p))
469 {
470 sendto_one(source_p, form_str(ERR_NOPRIVS),
471 me.name, source_p->name, "admin");
472 return 0;
473 }
474
475 for (i = 0; i < num_mods; i++)
476 {
477 if(parc > 1)
478 {
479 if(match(parv[1], modlist[i]->name))
480 {
481 sendto_one(source_p, form_str(RPL_MODLIST),
482 me.name, source_p->name,
483 modlist[i]->name,
484 modlist[i]->address,
485 modlist[i]->version, modlist[i]->core ? "(core)" : "");
486 }
487 }
488 else
489 {
490 sendto_one(source_p, form_str(RPL_MODLIST),
491 me.name, source_p->name, modlist[i]->name,
492 modlist[i]->address, modlist[i]->version,
493 modlist[i]->core ? "(core)" : "");
494 }
495 }
496
497 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
498 return 0;
499 }
500
501 /* unload and reload all modules */
502 static int
503 mo_modrestart(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
504 {
505 int modnum;
506
507 if(!IsOperAdmin(source_p))
508 {
509 sendto_one(source_p, form_str(ERR_NOPRIVS),
510 me.name, source_p->name, "admin");
511 return 0;
512 }
513
514 sendto_one_notice(source_p, ":Reloading all modules");
515
516 modnum = num_mods;
517 while (num_mods)
518 unload_one_module(modlist[0]->name, 0);
519
520 load_all_modules(0);
521 load_core_modules(0);
522 rehash(0);
523
524 sendto_realops_snomask(SNO_GENERAL, L_ALL,
525 "Module Restart: %d modules unloaded, %d modules loaded",
526 modnum, num_mods);
527 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
528 return 0;
529 }
530
531
532
533 #ifndef RTLD_NOW
534 #define RTLD_NOW RTLD_LAZY /* openbsd deficiency */
535 #endif
536
537 #ifdef CHARYBDIS_PROFILE
538 # ifndef RTLD_PROFILE
539 # warning libdl may not support profiling, sucks. :(
540 # define RTLD_PROFILE 0
541 # endif
542 #endif
543
544 static void increase_modlist(void);
545
546 #define MODS_INCREMENT 10
547
548 static char unknown_ver[] = "<unknown>";
549
550 /* This file contains the core functions to use dynamic libraries.
551 * -TimeMr14C
552 */
553
554
555 #ifdef HAVE_MACH_O_DYLD_H
556 /*
557 ** jmallett's dl*(3) shims for NSModule(3) systems.
558 */
559 #include <mach-o/dyld.h>
560
561 #ifndef HAVE_DLOPEN
562 #ifndef RTLD_LAZY
563 #define RTLD_LAZY 2185 /* built-in dl*(3) don't care */
564 #endif
565
566 void undefinedErrorHandler(const char *);
567 NSModule multipleErrorHandler(NSSymbol, NSModule, NSModule);
568 void linkEditErrorHandler(NSLinkEditErrors, int, const char *, const char *);
569 char *dlerror(void);
570 void *dlopen(char *, int);
571 int dlclose(void *);
572 void *dlsym(void *, char *);
573
574 static int firstLoad = TRUE;
575 static int myDlError;
576 static char *myErrorTable[] = { "Loading file as object failed\n",
577 "Loading file as object succeeded\n",
578 "Not a valid shared object\n",
579 "Architecture of object invalid on this architecture\n",
580 "Invalid or corrupt image\n",
581 "Could not access object\n",
582 "NSCreateObjectFileImageFromFile failed\n",
583 NULL
584 };
585
586 void
587 undefinedErrorHandler(const char *symbolName)
588 {
589 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Undefined symbol: %s", symbolName);
590 ilog(L_MAIN, "Undefined symbol: %s", symbolName);
591 return;
592 }
593
594 NSModule
595 multipleErrorHandler(NSSymbol s, NSModule old, NSModule new)
596 {
597 /* XXX
598 ** This results in substantial leaking of memory... Should free one
599 ** module, maybe?
600 */
601 sendto_realops_snomask(SNO_GENERAL, L_ALL,
602 "Symbol `%s' found in `%s' and `%s'",
603 NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
604 ilog(L_MAIN, "Symbol `%s' found in `%s' and `%s'",
605 NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
606 /* We return which module should be considered valid, I believe */
607 return new;
608 }
609
610 void
611 linkEditErrorHandler(NSLinkEditErrors errorClass, int errnum,
612 const char *fileName, const char *errorString)
613 {
614 sendto_realops_snomask(SNO_GENERAL, L_ALL,
615 "Link editor error: %s for %s", errorString, fileName);
616 ilog(L_MAIN, "Link editor error: %s for %s", errorString, fileName);
617 return;
618 }
619
620 char *
621 dlerror(void)
622 {
623 return myDlError == NSObjectFileImageSuccess ? NULL : myErrorTable[myDlError % 7];
624 }
625
626 void *
627 dlopen(char *filename, int unused)
628 {
629 NSObjectFileImage myImage;
630 NSModule myModule;
631
632 if(firstLoad)
633 {
634 /*
635 ** If we are loading our first symbol (huzzah!) we should go ahead
636 ** and install link editor error handling!
637 */
638 NSLinkEditErrorHandlers linkEditorErrorHandlers;
639
640 linkEditorErrorHandlers.undefined = undefinedErrorHandler;
641 linkEditorErrorHandlers.multiple = multipleErrorHandler;
642 linkEditorErrorHandlers.linkEdit = linkEditErrorHandler;
643 NSInstallLinkEditErrorHandlers(&linkEditorErrorHandlers);
644 firstLoad = FALSE;
645 }
646 myDlError = NSCreateObjectFileImageFromFile(filename, &myImage);
647 if(myDlError != NSObjectFileImageSuccess)
648 {
649 return NULL;
650 }
651 myModule = NSLinkModule(myImage, filename, NSLINKMODULE_OPTION_PRIVATE);
652 return (void *) myModule;
653 }
654
655 int
656 dlclose(void *myModule)
657 {
658 NSUnLinkModule(myModule, FALSE);
659 return 0;
660 }
661
662 void *
663 dlsym(void *myModule, char *mySymbolName)
664 {
665 NSSymbol mySymbol;
666
667 mySymbol = NSLookupSymbolInModule((NSModule) myModule, mySymbolName);
668 return NSAddressOfSymbol(mySymbol);
669 }
670 #endif
671 #endif
672
673
674 /*
675 * HPUX dl compat functions
676 */
677 #if defined(HAVE_SHL_LOAD) && !defined(HAVE_DLOPEN)
678 #define RTLD_LAZY BIND_DEFERRED
679 #define RTLD_GLOBAL DYNAMIC_PATH
680 #define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
681 #define dlclose(handle) shl_unload((shl_t)(handle))
682 #define dlsym(handle,name) hpux_dlsym(handle,name)
683 #define dlerror() strerror(errno)
684
685 static void *
686 hpux_dlsym(void *handle, char *name)
687 {
688 void *sym_addr;
689 if(!shl_findsym((shl_t *) & handle, name, TYPE_UNDEFINED, &sym_addr))
690 return sym_addr;
691 return NULL;
692 }
693
694 #endif
695
696 /* unload_one_module()
697 *
698 * inputs - name of module to unload
699 * - 1 to say modules unloaded, 0 to not
700 * output - 0 if successful, -1 if error
701 * side effects - module is unloaded
702 */
703 int
704 unload_one_module(const char *name, int warn)
705 {
706 int modindex;
707
708 if((modindex = findmodule_byname(name)) == -1)
709 return -1;
710
711 /*
712 ** XXX - The type system in C does not allow direct conversion between
713 ** data and function pointers, but as it happens, most C compilers will
714 ** safely do this, however it is a theoretical overlow to cast as we
715 ** must do here. I have library functions to take care of this, but
716 ** despite being more "correct" for the C language, this is more
717 ** practical. Removing the abuse of the ability to cast ANY pointer
718 ** to and from an integer value here will break some compilers.
719 ** -jmallett
720 */
721 /* Left the comment in but the code isn't here any more -larne */
722 switch (modlist[modindex]->mapi_version)
723 {
724 case 1:
725 {
726 struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
727 if(mheader->mapi_command_list)
728 {
729 struct Message **m;
730 for (m = mheader->mapi_command_list; *m; ++m)
731 mod_del_cmd(*m);
732 }
733
734 /* hook events are never removed, we simply lose the
735 * ability to call them --fl
736 */
737 if(mheader->mapi_hfn_list)
738 {
739 mapi_hfn_list_av1 *m;
740 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
741 remove_hook(m->hapi_name, m->fn);
742 }
743
744 if(mheader->mapi_unregister)
745 mheader->mapi_unregister();
746 break;
747 }
748 default:
749 sendto_realops_snomask(SNO_GENERAL, L_ALL,
750 "Unknown/unsupported MAPI version %d when unloading %s!",
751 modlist[modindex]->mapi_version, modlist[modindex]->name);
752 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
753 modlist[modindex]->mapi_version, modlist[modindex]->name);
754 break;
755 }
756
757 dlclose(modlist[modindex]->address);
758
759 rb_free(modlist[modindex]->name);
760 memcpy(&modlist[modindex], &modlist[modindex + 1],
761 sizeof(struct module) * ((num_mods - 1) - modindex));
762
763 if(num_mods != 0)
764 num_mods--;
765
766 if(warn == 1)
767 {
768 ilog(L_MAIN, "Module %s unloaded", name);
769 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
770 }
771
772 return 0;
773 }
774
775
776 /*
777 * load_a_module()
778 *
779 * inputs - path name of module, int to notice, int of core
780 * output - -1 if error 0 if success
781 * side effects - loads a module if successful
782 */
783 int
784 load_a_module(const char *path, int warn, int core)
785 {
786 void *tmpptr = NULL;
787
788 char *mod_basename;
789 const char *ver;
790
791 int *mapi_version;
792
793 mod_basename = irc_basename(path);
794
795 #ifdef CHARYBDIS_PROFILE
796 tmpptr = dlopen(path, RTLD_NOW | RTLD_PROFILE);
797 #else
798 tmpptr = dlopen(path, RTLD_NOW);
799 #endif
800
801 if(tmpptr == NULL)
802 {
803 const char *err = dlerror();
804
805 sendto_realops_snomask(SNO_GENERAL, L_ALL,
806 "Error loading module %s: %s", mod_basename, err);
807 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
808 rb_free(mod_basename);
809 return -1;
810 }
811
812
813 /*
814 * _mheader is actually a struct mapi_mheader_*, but mapi_version
815 * is always the first member of this structure, so we treate it
816 * as a single int in order to determine the API version.
817 * -larne.
818 */
819 mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "_mheader");
820 if((mapi_version == NULL
821 && (mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "__mheader")) == NULL)
822 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
823 {
824 sendto_realops_snomask(SNO_GENERAL, L_ALL,
825 "Data format error: module %s has no MAPI header.",
826 mod_basename);
827 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
828 (void) dlclose(tmpptr);
829 rb_free(mod_basename);
830 return -1;
831 }
832
833 switch (MAPI_VERSION(*mapi_version))
834 {
835 case 1:
836 {
837 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *) mapi_version; /* see above */
838 if(mheader->mapi_register && (mheader->mapi_register() == -1))
839 {
840 ilog(L_MAIN, "Module %s indicated failure during load.",
841 mod_basename);
842 sendto_realops_snomask(SNO_GENERAL, L_ALL,
843 "Module %s indicated failure during load.",
844 mod_basename);
845 dlclose(tmpptr);
846 rb_free(mod_basename);
847 return -1;
848 }
849 if(mheader->mapi_command_list)
850 {
851 struct Message **m;
852 for (m = mheader->mapi_command_list; *m; ++m)
853 mod_add_cmd(*m);
854 }
855
856 if(mheader->mapi_hook_list)
857 {
858 mapi_hlist_av1 *m;
859 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
860 *m->hapi_id = register_hook(m->hapi_name);
861 }
862
863 if(mheader->mapi_hfn_list)
864 {
865 mapi_hfn_list_av1 *m;
866 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
867 add_hook(m->hapi_name, m->fn);
868 }
869
870 ver = mheader->mapi_module_version;
871 break;
872 }
873
874 default:
875 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
876 mod_basename, MAPI_VERSION(*mapi_version));
877 sendto_realops_snomask(SNO_GENERAL, L_ALL,
878 "Module %s has unknown/unsupported MAPI version %d.",
879 mod_basename, *mapi_version);
880 dlclose(tmpptr);
881 rb_free(mod_basename);
882 return -1;
883 }
884
885 if(ver == NULL)
886 ver = unknown_ver;
887
888 increase_modlist();
889
890 modlist[num_mods] = rb_malloc(sizeof(struct module));
891 modlist[num_mods]->address = tmpptr;
892 modlist[num_mods]->version = ver;
893 modlist[num_mods]->core = core;
894 modlist[num_mods]->name = rb_strdup(mod_basename);
895 modlist[num_mods]->mapi_header = mapi_version;
896 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
897 num_mods++;
898
899 if(warn == 1)
900 {
901 sendto_realops_snomask(SNO_GENERAL, L_ALL,
902 "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
903 mod_basename, ver, MAPI_VERSION(*mapi_version),
904 (unsigned long) tmpptr);
905 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
906 mod_basename, ver, MAPI_VERSION(*mapi_version), (unsigned long) tmpptr);
907 }
908 rb_free(mod_basename);
909 return 0;
910 }
911
912 /*
913 * increase_modlist
914 *
915 * inputs - NONE
916 * output - NONE
917 * side effects - expand the size of modlist if necessary
918 */
919 static void
920 increase_modlist(void)
921 {
922 struct module **new_modlist = NULL;
923
924 if((num_mods + 1) < max_mods)
925 return;
926
927 new_modlist = (struct module **) rb_malloc(sizeof(struct module) *
928 (max_mods + MODS_INCREMENT));
929 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module) * num_mods);
930
931 rb_free(modlist);
932 modlist = new_modlist;
933 max_mods += MODS_INCREMENT;
934 }
935
936 #else /* STATIC_MODULES */
937
938 /* load_all_modules()
939 *
940 * input -
941 * output -
942 * side effects - all the msgtabs are added for static modules
943 */
944 void
945 load_all_modules(int warn)
946 {
947 load_static_modules();
948 }
949
950 #endif /* STATIC_MODULES */